diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md
index e5a3ddd47c71bbc4ddfabfb48d9cc134a38d481f..29d052ad49999699842682e57ad45363ff4f4a6e 100644
--- a/docs/usage/self-hosted-configuration.md
+++ b/docs/usage/self-hosted-configuration.md
@@ -1084,6 +1084,10 @@ For TLS/SSL-enabled connections, use rediss prefix
 
 Example URL structure: `rediss://[[username]:[password]]@localhost:6379/0`.
 
+Renovate also supports connecting to Redis clusters as well. In order to connect to a cluster, provide the connection string using the `redis+cluster` or `rediss+cluster` schema as appropriate.
+
+Example URL structure: `redis+cluster://[[username]:[password]]@redis.cluster.local:6379/0`
+
 ## reportPath
 
 `reportPath` describes the location where the report is written to.
diff --git a/lib/util/cache/package/redis.spec.ts b/lib/util/cache/package/redis.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e43db0768de9e158ec0ab1c61b06a5d1cec80743
--- /dev/null
+++ b/lib/util/cache/package/redis.spec.ts
@@ -0,0 +1,29 @@
+import { normalizeRedisUrl } from './redis';
+
+describe('util/cache/package/redis', () => {
+  describe('normalizeRedisUrl', () => {
+    it('leaves standard Redis URL alone', () => {
+      const url = 'redis://user:password@localhost:6379';
+      expect(normalizeRedisUrl(url)).toBe(url);
+    });
+
+    it('leaves secure Redis URL alone', () => {
+      const url = 'rediss://user:password@localhost:6379';
+      expect(normalizeRedisUrl(url)).toBe(url);
+    });
+
+    it('rewrites standard Redis Cluster URL', () => {
+      const url = 'redis+cluster://user:password@localhost:6379';
+      expect(normalizeRedisUrl(url)).toBe(
+        'redis://user:password@localhost:6379',
+      );
+    });
+
+    it('rewrites secure Redis Cluster URL', () => {
+      const url = 'rediss+cluster://user:password@localhost:6379';
+      expect(normalizeRedisUrl(url)).toBe(
+        'rediss://user:password@localhost:6379',
+      );
+    });
+  });
+});
diff --git a/lib/util/cache/package/redis.ts b/lib/util/cache/package/redis.ts
index 259103b1245c951c4e6cbd70278c78095173675c..24c36a8d4ab6c4c21184179c2eb615754d5b9e54 100644
--- a/lib/util/cache/package/redis.ts
+++ b/lib/util/cache/package/redis.ts
@@ -1,17 +1,25 @@
 /* istanbul ignore file */
 import { DateTime } from 'luxon';
-import { createClient } from 'redis';
+import { createClient, createCluster } from 'redis';
 import { logger } from '../../../logger';
 import { compressToBase64, decompressFromBase64 } from '../../compress';
+import { regEx } from '../../regex';
 import type { PackageCacheNamespace } from './types';
 
-let client: ReturnType<typeof createClient> | undefined;
+let client:
+  | ReturnType<typeof createClient>
+  | ReturnType<typeof createCluster>
+  | undefined;
 let rprefix: string | undefined;
 
 function getKey(namespace: PackageCacheNamespace, key: string): string {
   return `${rprefix}${namespace}-${key}`;
 }
 
+export function normalizeRedisUrl(url: string): string {
+  return url.replace(regEx(/^(rediss?)\+cluster:\/\//), '$1://');
+}
+
 export async function end(): Promise<void> {
   try {
     // https://github.com/redis/node-redis#disconnecting
@@ -94,16 +102,28 @@ export async function init(
   }
   rprefix = prefix ?? '';
   logger.debug('Redis cache init');
-  client = createClient({
-    url,
+
+  const rewrittenUrl = normalizeRedisUrl(url);
+  // If any replacement was made, it means the regex matched and we are in clustered mode
+  const clusteredMode = rewrittenUrl.length !== url.length;
+
+  const config = {
+    url: rewrittenUrl,
     socket: {
-      reconnectStrategy: (retries) => {
+      reconnectStrategy: (retries: number) => {
         // Reconnect after this time
         return Math.min(retries * 100, 3000);
       },
     },
     pingInterval: 30000, // 30s
-  });
+  };
+  if (clusteredMode) {
+    client = createCluster({
+      rootNodes: [config],
+    });
+  } else {
+    client = createClient(config);
+  }
   await client.connect();
   logger.debug('Redis cache connected');
 }