diff --git a/package-lock.json b/package-lock.json
index 78feb73b2c..21eeebac22 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8520,7 +8520,7 @@
     },
     "packages/bloom": {
       "name": "@redis/bloom",
-      "version": "5.1.0",
+      "version": "5.1.1",
       "license": "MIT",
       "devDependencies": {
         "@redis/test-utils": "*"
@@ -8529,12 +8529,12 @@
         "node": ">= 18"
       },
       "peerDependencies": {
-        "@redis/client": "^5.1.0"
+        "@redis/client": "^5.1.1"
       }
     },
     "packages/client": {
       "name": "@redis/client",
-      "version": "5.1.0",
+      "version": "5.1.1",
       "license": "MIT",
       "dependencies": {
         "cluster-key-slot": "1.1.2"
@@ -8550,7 +8550,7 @@
     },
     "packages/entraid": {
       "name": "@redis/entraid",
-      "version": "5.1.0",
+      "version": "5.1.1",
       "license": "MIT",
       "dependencies": {
         "@azure/identity": "^4.7.0",
@@ -8569,7 +8569,7 @@
         "node": ">= 18"
       },
       "peerDependencies": {
-        "@redis/client": "^5.1.0"
+        "@redis/client": "^5.1.1"
       }
     },
     "packages/entraid/node_modules/@types/node": {
@@ -8606,7 +8606,7 @@
     },
     "packages/json": {
       "name": "@redis/json",
-      "version": "5.0.1",
+      "version": "5.1.0",
       "license": "MIT",
       "devDependencies": {
         "@redis/test-utils": "*"
@@ -8615,39 +8615,39 @@
         "node": ">= 18"
       },
       "peerDependencies": {
-        "@redis/client": "^5.1.0"
+        "@redis/client": "^5.1.1"
       }
     },
     "packages/redis": {
-      "version": "5.0.1",
+      "version": "5.1.0",
       "license": "MIT",
       "dependencies": {
-        "@redis/bloom": "5.0.1",
-        "@redis/client": "5.0.1",
-        "@redis/json": "5.0.1",
-        "@redis/search": "5.0.1",
-        "@redis/time-series": "5.0.1"
+        "@redis/bloom": "5.1.0",
+        "@redis/client": "5.1.0",
+        "@redis/json": "5.1.0",
+        "@redis/search": "5.1.0",
+        "@redis/time-series": "5.1.0"
       },
       "engines": {
         "node": ">= 18"
       }
     },
     "packages/redis/node_modules/@redis/bloom": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.0.1.tgz",
-      "integrity": "sha512-F7L+rnuJvq/upKaVoEgsf8VT7g5pLQYWRqSUOV3uO4vpVtARzSKJ7CLyJjVsQS+wZVCGxsLMh8DwAIDcny1B+g==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.1.0.tgz",
+      "integrity": "sha512-Gp5RWvVKbvItMU2sd848yhY/BnigToz8H4PYcvlBBSP5cQ3lVP1LMh5Kx2CYBNzCdDabVicwBKNvaoLBqPNqIg==",
       "license": "MIT",
       "engines": {
         "node": ">= 18"
       },
       "peerDependencies": {
-        "@redis/client": "^5.0.1"
+        "@redis/client": "^5.1.0"
       }
     },
     "packages/redis/node_modules/@redis/client": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.0.1.tgz",
-      "integrity": "sha512-k0EJvlMGEyBqUD3orKe0UMZ66fPtfwqPIr+ZSd853sXj2EyhNtPXSx+J6sENXJNgAlEBhvD+57Dwt0qTisKB0A==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.1.0.tgz",
+      "integrity": "sha512-FMD35y2KgCWTBLOfF0MhwDSaIVcu5mOUuTV9Kw3JOWHMgON3+ulht31cjTB/gph0BfD1vzUvCeROeRaf/d+35w==",
       "license": "MIT",
       "dependencies": {
         "cluster-key-slot": "1.1.2"
@@ -8658,7 +8658,7 @@
     },
     "packages/search": {
       "name": "@redis/search",
-      "version": "5.0.1",
+      "version": "5.1.0",
       "license": "MIT",
       "devDependencies": {
         "@redis/test-utils": "*"
@@ -8667,7 +8667,7 @@
         "node": ">= 18"
       },
       "peerDependencies": {
-        "@redis/client": "^5.0.1"
+        "@redis/client": "^5.1.0"
       }
     },
     "packages/test-utils": {
@@ -8736,7 +8736,7 @@
     },
     "packages/time-series": {
       "name": "@redis/time-series",
-      "version": "5.0.1",
+      "version": "5.1.0",
       "license": "MIT",
       "devDependencies": {
         "@redis/test-utils": "*"
@@ -8745,7 +8745,7 @@
         "node": ">= 18"
       },
       "peerDependencies": {
-        "@redis/client": "^5.0.1"
+        "@redis/client": "^5.1.0"
       }
     }
   }
diff --git a/packages/bloom/package.json b/packages/bloom/package.json
index 3c8e37c5b7..547e5ee64e 100644
--- a/packages/bloom/package.json
+++ b/packages/bloom/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/bloom",
-  "version": "5.1.0",
+  "version": "5.1.1",
   "license": "MIT",
   "main": "./dist/lib/index.js",
   "types": "./dist/lib/index.d.ts",
@@ -12,7 +12,7 @@
     "test": "nyc -r text-summary -r lcov mocha -r tsx './lib/**/*.spec.ts'"
   },
   "peerDependencies": {
-    "@redis/client": "^5.1.0"
+    "@redis/client": "^5.1.1"
   },
   "devDependencies": {
     "@redis/test-utils": "*"
diff --git a/packages/client/lib/client/index.spec.ts b/packages/client/lib/client/index.spec.ts
index cc052dd5b5..4f752210db 100644
--- a/packages/client/lib/client/index.spec.ts
+++ b/packages/client/lib/client/index.spec.ts
@@ -89,8 +89,8 @@ describe('Client', () => {
         && expected?.credentialsProvider?.type === 'async-credentials-provider') {
 
         // Compare the actual output of the credentials functions
-        const resultCreds = await result.credentialsProvider.credentials();
-        const expectedCreds = await expected.credentialsProvider.credentials();
+        const resultCreds = await result.credentialsProvider?.credentials();
+        const expectedCreds = await expected.credentialsProvider?.credentials();
         assert.deepEqual(resultCreds, expectedCreds);
       } else {
         assert.fail('Credentials provider type mismatch');
diff --git a/packages/client/lib/client/index.ts b/packages/client/lib/client/index.ts
index 8d98aa8ed2..a446ad8e75 100644
--- a/packages/client/lib/client/index.ts
+++ b/packages/client/lib/client/index.ts
@@ -4,7 +4,7 @@ import { BasicAuth, CredentialsError, CredentialsProvider, StreamingCredentialsP
 import RedisCommandsQueue, { CommandOptions } from './commands-queue';
 import { EventEmitter } from 'node:events';
 import { attachConfig, functionArgumentsPrefix, getTransformReply, scriptArgumentsPrefix } from '../commander';
-import { ClientClosedError, ClientOfflineError, DisconnectsClientError, SimpleError, WatchError } from '../errors';
+import { ClientClosedError, ClientOfflineError, DisconnectsClientError, WatchError } from '../errors';
 import { URL } from 'node:url';
 import { TcpSocketConnectOpts } from 'node:net';
 import { PUBSUB_TYPE, PubSubType, PubSubListener, PubSubTypeListeners, ChannelListeners } from './pub-sub';
@@ -626,14 +626,10 @@ export default class RedisClient<
     if (!this.#options?.disableClientInfo) {
       commands.push({
         cmd: ['CLIENT', 'SETINFO', 'LIB-VER', version],
-        errorHandler: (err: Error) => {
-          // Only throw if not a SimpleError - unknown subcommand
-          // Client libraries are expected to ignore failures
-          // of type SimpleError - unknown subcommand, which are
-          // expected from older servers ( < v7 )
-          if (!(err instanceof SimpleError) || !err.isUnknownSubcommand()) {
-            throw err;
-          }
+        errorHandler: () => {
+          // Client libraries are expected to pipeline this command
+          // after authentication on all connections and ignore failures
+          // since they could be connected to an older version that doesn't support them.
         }
       });
       
@@ -646,14 +642,10 @@ export default class RedisClient<
             ? `node-redis(${this.#options.clientInfoTag})`
             : 'node-redis'
         ],
-        errorHandler: (err: Error) => {
-          // Only throw if not a SimpleError - unknown subcommand
-          // Client libraries are expected to ignore failures
-          // of type SimpleError - unknown subcommand, which are
-          // expected from older servers ( < v7 )
-          if (!(err instanceof SimpleError) || !err.isUnknownSubcommand()) {
-            throw err;
-          }
+        errorHandler: () => {
+          // Client libraries are expected to pipeline this command
+          // after authentication on all connections and ignore failures
+          // since they could be connected to an older version that doesn't support them.
         }
       });
     }
diff --git a/packages/client/lib/cluster/index.ts b/packages/client/lib/cluster/index.ts
index f738562926..c2c251810e 100644
--- a/packages/client/lib/cluster/index.ts
+++ b/packages/client/lib/cluster/index.ts
@@ -188,7 +188,7 @@ export default class RedisCluster<
       const parser = new BasicCommandParser();
       command.parseCommand(parser, ...args);
 
-      return this._self.#execute(
+      return this._self._execute(
         parser.firstKey,
         command.IS_READ_ONLY,
         this._commandOptions,
@@ -204,7 +204,7 @@ export default class RedisCluster<
       const parser = new BasicCommandParser();
       command.parseCommand(parser, ...args);
 
-      return this._self.#execute(
+      return this._self._execute(
         parser.firstKey,
         command.IS_READ_ONLY,
         this._self._commandOptions,
@@ -222,7 +222,7 @@ export default class RedisCluster<
       parser.push(...prefix);
       fn.parseCommand(parser, ...args);
 
-      return this._self.#execute(
+      return this._self._execute(
         parser.firstKey,
         fn.IS_READ_ONLY,
         this._self._commandOptions,
@@ -240,7 +240,7 @@ export default class RedisCluster<
       parser.push(...prefix);
       script.parseCommand(parser, ...args);
 
-      return this._self.#execute(
+      return this._self._execute(
         parser.firstKey,
         script.IS_READ_ONLY,
         this._commandOptions,
@@ -293,9 +293,9 @@ export default class RedisCluster<
     return RedisCluster.factory(options)(options);
   }
 
-  readonly #options: RedisClusterOptions<M, F, S, RESP, TYPE_MAPPING/*, POLICIES*/>;
+  readonly _options: RedisClusterOptions<M, F, S, RESP, TYPE_MAPPING/*, POLICIES*/>;
 
-  readonly #slots: RedisClusterSlots<M, F, S, RESP, TYPE_MAPPING>;
+  readonly _slots: RedisClusterSlots<M, F, S, RESP, TYPE_MAPPING>;
 
   private _self = this;
   private _commandOptions?: ClusterCommandOptions<TYPE_MAPPING/*, POLICIES*/>;
@@ -305,11 +305,11 @@ export default class RedisCluster<
    * Use with {@link RedisCluster.prototype.nodeClient} to get the client for a specific node (master or replica).
    */
   get slots() {
-    return this._self.#slots.slots;
+    return this._self._slots.slots;
   }
 
   get clientSideCache() {
-    return this._self.#slots.clientSideCache;
+    return this._self._slots.clientSideCache;
   }
 
   /**
@@ -317,7 +317,7 @@ export default class RedisCluster<
    * Use with {@link RedisCluster.prototype.nodeClient} to get the client for a specific master node.
    */
   get masters() {
-    return this._self.#slots.masters;
+    return this._self._slots.masters;
   }
 
   /**
@@ -325,7 +325,7 @@ export default class RedisCluster<
    * Use with {@link RedisCluster.prototype.nodeClient} to get the client for a specific replica node.
    */
   get replicas() {
-    return this._self.#slots.replicas;
+    return this._self._slots.replicas;
   }
 
   /**
@@ -333,25 +333,25 @@ export default class RedisCluster<
    * Use with {@link RedisCluster.prototype.nodeClient} to get the client for a specific node (master or replica).
    */
   get nodeByAddress() {
-    return this._self.#slots.nodeByAddress;
+    return this._self._slots.nodeByAddress;
   }
 
   /**
    * The current pub/sub node.
    */
   get pubSubNode() {
-    return this._self.#slots.pubSubNode;
+    return this._self._slots.pubSubNode;
   }
 
   get isOpen() {
-    return this._self.#slots.isOpen;
+    return this._self._slots.isOpen;
   }
 
   constructor(options: RedisClusterOptions<M, F, S, RESP, TYPE_MAPPING/*, POLICIES*/>) {
     super();
 
-    this.#options = options;
-    this.#slots = new RedisClusterSlots(options, this.emit.bind(this));
+    this._options = options;
+    this._slots = new RedisClusterSlots(options, this.emit.bind(this));
 
     if (options?.commandOptions) {
       this._commandOptions = options.commandOptions;
@@ -366,14 +366,14 @@ export default class RedisCluster<
     _TYPE_MAPPING extends TypeMapping = TYPE_MAPPING
   >(overrides?: Partial<RedisClusterOptions<_M, _F, _S, _RESP, _TYPE_MAPPING>>) {
     return new (Object.getPrototypeOf(this).constructor)({
-      ...this._self.#options,
+      ...this._self._options,
       commandOptions: this._commandOptions,
       ...overrides
     }) as RedisClusterType<_M, _F, _S, _RESP, _TYPE_MAPPING>;
   }
 
   async connect() {
-    await this._self.#slots.connect();
+    await this._self._slots.connect();
     return this as unknown as RedisClusterType<M, F, S, RESP, TYPE_MAPPING>;
   }
 
@@ -429,7 +429,7 @@ export default class RedisCluster<
   //   return this._commandOptionsProxy('policies', policies);
   // }
 
-  #handleAsk<T>(
+  _handleAsk<T>(
     fn: (client: RedisClientType<M, F, S, RESP, TYPE_MAPPING>, opts?: ClusterCommandOptions) => Promise<T>
   ) {
     return async (client: RedisClientType<M, F, S, RESP, TYPE_MAPPING>, options?: ClusterCommandOptions) => {
@@ -450,14 +450,14 @@ export default class RedisCluster<
     };
   }
 
-  async #execute<T>(
+  async _execute<T>(
     firstKey: RedisArgument | undefined,
     isReadonly: boolean | undefined,
     options: ClusterCommandOptions | undefined,
     fn: (client: RedisClientType<M, F, S, RESP, TYPE_MAPPING>, opts?: ClusterCommandOptions) => Promise<T>
   ): Promise<T> {
-    const maxCommandRedirections = this.#options.maxCommandRedirections ?? 16;
-    let client = await this.#slots.getClient(firstKey, isReadonly);
+    const maxCommandRedirections = this._options.maxCommandRedirections ?? 16;
+    let client = await this._slots.getClient(firstKey, isReadonly);
     let i = 0;
 
     let myFn = fn;
@@ -475,10 +475,10 @@ export default class RedisCluster<
 
         if (err.message.startsWith('ASK')) {
           const address = err.message.substring(err.message.lastIndexOf(' ') + 1);
-          let redirectTo = await this.#slots.getMasterByAddress(address);
+          let redirectTo = await this._slots.getMasterByAddress(address);
           if (!redirectTo) {
-            await this.#slots.rediscover(client);
-            redirectTo = await this.#slots.getMasterByAddress(address);
+            await this._slots.rediscover(client);
+            redirectTo = await this._slots.getMasterByAddress(address);
           }
 
           if (!redirectTo) {
@@ -486,13 +486,13 @@ export default class RedisCluster<
           }
 
           client = redirectTo;
-          myFn = this.#handleAsk(fn);
+          myFn = this._handleAsk(fn);
           continue;
         }
         
         if (err.message.startsWith('MOVED')) {
-          await this.#slots.rediscover(client);
-          client = await this.#slots.getClient(firstKey, isReadonly);
+          await this._slots.rediscover(client);
+          client = await this._slots.getClient(firstKey, isReadonly);
           continue;
         }
 
@@ -508,7 +508,7 @@ export default class RedisCluster<
     options?: ClusterCommandOptions,
     // defaultPolicies?: CommandPolicies
   ): Promise<T> {
-    return this._self.#execute(
+    return this._self._execute(
       firstKey,
       isReadonly,
       options,
@@ -520,11 +520,11 @@ export default class RedisCluster<
     type Multi = new (...args: ConstructorParameters<typeof RedisClusterMultiCommand>) => RedisClusterMultiCommandType<[], M, F, S, RESP, TYPE_MAPPING>;
     return new ((this as any).Multi as Multi)(
       async (firstKey, isReadonly, commands) => {
-        const client = await this._self.#slots.getClient(firstKey, isReadonly);
+        const client = await this._self._slots.getClient(firstKey, isReadonly);
         return client._executeMulti(commands);
       },
       async (firstKey, isReadonly, commands) => {
-        const client = await this._self.#slots.getClient(firstKey, isReadonly);
+        const client = await this._self._slots.getClient(firstKey, isReadonly);
         return client._executePipeline(commands);
       },
       routing,
@@ -539,7 +539,7 @@ export default class RedisCluster<
     listener: PubSubListener<T>,
     bufferMode?: T
   ) {
-    return (await this._self.#slots.getPubSubClient())
+    return (await this._self._slots.getPubSubClient())
       .SUBSCRIBE(channels, listener, bufferMode);
   }
 
@@ -550,7 +550,7 @@ export default class RedisCluster<
     listener?: PubSubListener<boolean>,
     bufferMode?: T
   ) {
-    return this._self.#slots.executeUnsubscribeCommand(client =>
+    return this._self._slots.executeUnsubscribeCommand(client =>
       client.UNSUBSCRIBE(channels, listener, bufferMode)
     );
   }
@@ -562,7 +562,7 @@ export default class RedisCluster<
     listener: PubSubListener<T>,
     bufferMode?: T
   ) {
-    return (await this._self.#slots.getPubSubClient())
+    return (await this._self._slots.getPubSubClient())
       .PSUBSCRIBE(patterns, listener, bufferMode);
   }
 
@@ -573,7 +573,7 @@ export default class RedisCluster<
     listener?: PubSubListener<T>,
     bufferMode?: T
   ) {
-    return this._self.#slots.executeUnsubscribeCommand(client =>
+    return this._self._slots.executeUnsubscribeCommand(client =>
       client.PUNSUBSCRIBE(patterns, listener, bufferMode)
     );
   }
@@ -585,9 +585,9 @@ export default class RedisCluster<
     listener: PubSubListener<T>,
     bufferMode?: T
   ) {
-    const maxCommandRedirections = this._self.#options.maxCommandRedirections ?? 16,
+    const maxCommandRedirections = this._self._options.maxCommandRedirections ?? 16,
       firstChannel = Array.isArray(channels) ? channels[0] : channels;
-    let client = await this._self.#slots.getShardedPubSubClient(firstChannel);
+    let client = await this._self._slots.getShardedPubSubClient(firstChannel);
     for (let i = 0; ; i++) {
       try {
         return await client.SSUBSCRIBE(channels, listener, bufferMode);
@@ -597,8 +597,8 @@ export default class RedisCluster<
         }
 
         if (err.message.startsWith('MOVED')) {
-          await this._self.#slots.rediscover(client);
-          client = await this._self.#slots.getShardedPubSubClient(firstChannel);
+          await this._self._slots.rediscover(client);
+          client = await this._self._slots.getShardedPubSubClient(firstChannel);
           continue;
         }
 
@@ -614,7 +614,7 @@ export default class RedisCluster<
     listener?: PubSubListener<T>,
     bufferMode?: T
   ) {
-    return this._self.#slots.executeShardedUnsubscribeCommand(
+    return this._self._slots.executeShardedUnsubscribeCommand(
       Array.isArray(channels) ? channels[0] : channels,
       client => client.SUNSUBSCRIBE(channels, listener, bufferMode)
     );
@@ -626,28 +626,28 @@ export default class RedisCluster<
    * @deprecated Use `close` instead.
    */
   quit() {
-    return this._self.#slots.quit();
+    return this._self._slots.quit();
   }
 
   /**
    * @deprecated Use `destroy` instead.
    */
   disconnect() {
-    return this._self.#slots.disconnect();
+    return this._self._slots.disconnect();
   }
 
   close() {
-    this._self.#slots.clientSideCache?.onPoolClose();
-    return this._self.#slots.close();
+    this._self._slots.clientSideCache?.onPoolClose();
+    return this._self._slots.close();
   }
 
   destroy() {
-    this._self.#slots.clientSideCache?.onPoolClose();
-    return this._self.#slots.destroy();
+    this._self._slots.clientSideCache?.onPoolClose();
+    return this._self._slots.destroy();
   }
 
   nodeClient(node: ShardNode<M, F, S, RESP, TYPE_MAPPING>) {
-    return this._self.#slots.nodeClient(node);
+    return this._self._slots.nodeClient(node);
   }
 
   /**
@@ -655,7 +655,7 @@ export default class RedisCluster<
    * Userful for running "forward" commands (like PUBLISH) on a random node.
    */
   getRandomNode() {
-    return this._self.#slots.getRandomNode();
+    return this._self._slots.getRandomNode();
   }
 
   /**
@@ -663,7 +663,7 @@ export default class RedisCluster<
    * Useful for running readonly commands on a slot.
    */
   getSlotRandomNode(slot: number) {
-    return this._self.#slots.getSlotRandomNode(slot);
+    return this._self._slots.getSlotRandomNode(slot);
   }
 
   /**
diff --git a/packages/client/lib/errors.ts b/packages/client/lib/errors.ts
index 4f05f62ac4..db37ec1a9b 100644
--- a/packages/client/lib/errors.ts
+++ b/packages/client/lib/errors.ts
@@ -70,11 +70,7 @@ export class ErrorReply extends Error {
   }
 }
 
-export class SimpleError extends ErrorReply {
-  isUnknownSubcommand(): boolean {
-    return this.message.toLowerCase().indexOf('err unknown subcommand') !== -1;
-  }
-}
+export class SimpleError extends ErrorReply {}
 
 export class BlobError extends ErrorReply {}
 
diff --git a/packages/client/lib/sentinel/index.spec.ts b/packages/client/lib/sentinel/index.spec.ts
index a2e52b774b..a9bdc8cc95 100644
--- a/packages/client/lib/sentinel/index.spec.ts
+++ b/packages/client/lib/sentinel/index.spec.ts
@@ -197,7 +197,6 @@ describe(`test with scripts`, () => {
   }, GLOBAL.SENTINEL.WITH_SCRIPT)
 });
 
-
 describe(`test with functions`, () => {
   testUtils.testWithClientSentinel('with function', async sentinel => {
     await sentinel.functionLoad(
@@ -377,12 +376,9 @@ describe(`test with masterPoolSize 2`, () => {
   }, GLOBAL.SENTINEL.WITH_MASTER_POOL_SIZE_2);
 });
 
-
-// TODO: Figure out how to modify the test utils
-// so it would have fine grained controll over
-// sentinel
-// it should somehow replicate the `SentinelFramework` object functionallities
 async function steadyState(frame: SentinelFramework) {
+  // wait a bit to ensure that sentinels are seeing eachother
+  await setTimeout(2000)
   let checkedMaster = false;
   let checkedReplicas = false;
   while (!checkedMaster || !checkedReplicas) {
@@ -430,7 +426,7 @@ async function steadyState(frame: SentinelFramework) {
   }
 }
 
-describe.skip('legacy tests', () => {
+describe('legacy tests', () => {
   const config: RedisSentinelConfig = { sentinelName: "test", numberOfNodes: 3, password: undefined };
   const frame = new SentinelFramework(config);
   let tracer = new Array<string>();
@@ -439,42 +435,30 @@ describe.skip('legacy tests', () => {
   let longestTestDelta = 0;
   let last: number;
 
-  before(async function () {
-    this.timeout(15000);
-
-    last = Date.now();
-
-    function deltaMeasurer() {
-      const delta = Date.now() - last;
-      if (delta > longestDelta) {
-        longestDelta = delta;
-      }
-      if (delta > longestTestDelta) {
-        longestTestDelta = delta;
-      }
-      if (!stopMeasuringBlocking) {
-        last = Date.now();
-        setImmediate(deltaMeasurer);
-      }
-    }
-    setImmediate(deltaMeasurer);
-    await frame.spawnRedisSentinel();
-  });
-
-  after(async function () {
-    this.timeout(15000);
-
-    stopMeasuringBlocking = true;
-
-    await frame.cleanup();
-  })
 
   describe('Sentinel Client', function () {
     let sentinel: RedisSentinelType<RedisModules, RedisFunctions, RedisScripts, RespVersions, TypeMapping> | undefined;
 
     beforeEach(async function () {
-      this.timeout(0);
-
+      this.timeout(15000);
+
+      last = Date.now();
+  
+      function deltaMeasurer() {
+        const delta = Date.now() - last;
+        if (delta > longestDelta) {
+          longestDelta = delta;
+        }
+        if (delta > longestTestDelta) {
+          longestTestDelta = delta;
+        }
+        if (!stopMeasuringBlocking) {
+          last = Date.now();
+          setImmediate(deltaMeasurer);
+        }
+      }
+      setImmediate(deltaMeasurer);
+      await frame.spawnRedisSentinel();
       await frame.getAllRunning();
       await steadyState(frame);
       longestTestDelta = 0;
@@ -522,6 +506,10 @@ describe.skip('legacy tests', () => {
         await sentinel.destroy();
         sentinel = undefined;
       }
+
+      stopMeasuringBlocking = true;
+  
+      await frame.cleanup();
     })
 
     it('use', async function () {
@@ -863,7 +851,6 @@ describe.skip('legacy tests', () => {
 
     it('shutdown sentinel node', async function () {
       this.timeout(60000);
-
       sentinel = frame.getSentinelClient();
       sentinel.setTracer(tracer);
       sentinel.on("error", () => { });
@@ -1020,7 +1007,7 @@ describe.skip('legacy tests', () => {
       this.timeout(30000);
       const csc = new BasicPooledClientSideCache();
 
-      sentinel = frame.getSentinelClient({nodeClientOptions: {RESP: 3}, clientSideCache: csc, masterPoolSize: 5});
+      sentinel = frame.getSentinelClient({nodeClientOptions: {RESP: 3 as const}, RESP: 3 as const, clientSideCache: csc, masterPoolSize: 5});
       await sentinel.connect();
 
       await sentinel.set('x', 1);
diff --git a/packages/client/lib/sentinel/test-util.ts b/packages/client/lib/sentinel/test-util.ts
index 86bc5b3178..60c1a59689 100644
--- a/packages/client/lib/sentinel/test-util.ts
+++ b/packages/client/lib/sentinel/test-util.ts
@@ -4,12 +4,13 @@ import { once } from 'node:events';
 import { promisify } from 'node:util';
 import { exec } from 'node:child_process';
 import { RedisSentinelOptions, RedisSentinelType } from './types';
-import RedisClient from '../client';
+import RedisClient, {RedisClientType} from '../client';
 import RedisSentinel from '.';
 import { RedisArgument, RedisFunctions, RedisModules, RedisScripts, RespVersions, TypeMapping } from '../RESP/types';
 const execAsync = promisify(exec);
 import RedisSentinelModule from './module'
-
+import TestUtils from '@redis/test-utils';
+import { DEBUG_MODE_ARGS } from '../test-utils'
 interface ErrorWithCode extends Error {
   code: string;
 }
@@ -125,7 +126,6 @@ export interface RedisSentinelConfig {
   sentinelServerArgument?: Array<string>
 
   sentinelName: string;
-  sentinelQuorum?: number;
 
   password?: string;
 }
@@ -151,6 +151,7 @@ export interface SentinelController {
 }
 
 export class SentinelFramework extends DockerBase {
+  #testUtils: TestUtils;
   #nodeList: Awaited<ReturnType<SentinelFramework['spawnRedisSentinelNodes']>> = [];
   /* port -> docker info/client */
   #nodeMap: Map<string, ArrayElement<Awaited<ReturnType<SentinelFramework['spawnRedisSentinelNodes']>>>>;
@@ -170,7 +171,11 @@ export class SentinelFramework extends DockerBase {
     super();
 
     this.config = config;
-
+    this.#testUtils = TestUtils.createFromConfig({
+      dockerImageName: 'redislabs/client-libs-test',
+      dockerImageVersionArgument: 'redis-version',
+      defaultDockerVersion: '8.0-M05-pre'
+    });
     this.#nodeMap = new Map<string, ArrayElement<Awaited<ReturnType<SentinelFramework['spawnRedisSentinelNodes']>>>>();
     this.#sentinelMap = new Map<string, ArrayElement<Awaited<ReturnType<SentinelFramework['spawnRedisSentinelSentinels']>>>>();
   }
@@ -190,7 +195,7 @@ export class SentinelFramework extends DockerBase {
     const options: RedisSentinelOptions<RedisModules, RedisFunctions, RedisScripts, RespVersions, TypeMapping> = {
       ...opts,
       name: this.config.sentinelName,
-      sentinelRootNodes: this.#sentinelList.map((sentinel) => { return { host: '127.0.0.1', port: sentinel.docker.port } }),
+      sentinelRootNodes: this.#sentinelList.map((sentinel) => { return { host: '127.0.0.1', port: sentinel.port } }),
       passthroughClientErrorEvents: errors
     }
 
@@ -218,11 +223,11 @@ export class SentinelFramework extends DockerBase {
       throw new Error("inconsistent state with partial setup");
     }
 
-    this.#nodeList = await this.spawnRedisSentinelNodes();
-    this.#nodeList.map((value) => this.#nodeMap.set(value.docker.port.toString(), value));
+    this.#nodeList = await this.spawnRedisSentinelNodes(2);
+    this.#nodeList.map((value) => this.#nodeMap.set(value.port.toString(), value));
 
-    this.#sentinelList = await this.spawnRedisSentinelSentinels();
-    this.#sentinelList.map((value) => this.#sentinelMap.set(value.docker.port.toString(), value));
+    this.#sentinelList = await this.spawnRedisSentinelSentinels(this.#nodeList[0].port, 3)
+    this.#sentinelList.map((value) => this.#sentinelMap.set(value.port.toString(), value));
 
     this.#spawned = true;
   }
@@ -234,11 +239,8 @@ export class SentinelFramework extends DockerBase {
 
     return Promise.all(
       [...this.#nodeMap!.values(), ...this.#sentinelMap!.values()].map(
-        async ({ docker, client }) => {
-          if (client.isOpen) {
-            client.destroy();
-          }
-          this.dockerRemove(docker.dockerId);
+        async ({ dockerId }) => {
+          this.dockerRemove(dockerId);
         }
       )
     ).finally(async () => {
@@ -248,112 +250,33 @@ export class SentinelFramework extends DockerBase {
     });
   }
 
-  protected async spawnRedisSentinelNodeDocker() {
-    const imageInfo: RedisServerDockerConfig = this.config.nodeDockerConfig ?? { image: "redis/redis-stack-server", version: "latest" };
-    const serverArguments: Array<string> = this.config.nodeServerArguments ?? [];
-    let environment;
-    if (this.config.password !== undefined) {
-      environment = `REDIS_ARGS="{port} --requirepass ${this.config.password}"`;
-    } else {
-      environment = 'REDIS_ARGS="{port}"';
-    }
-  
-    const docker = await this.spawnRedisServerDocker(imageInfo, serverArguments, environment);
-    const client = await RedisClient.create({
-      password: this.config.password,
-      socket: {
-        port: docker.port
-      }
-    }).on("error", () => { }).connect();
-
-    return {
-      docker,
-      client
-    };
-  }
-
-  protected async spawnRedisSentinelNodes() {
-    const master = await this.spawnRedisSentinelNodeDocker();
+  protected async spawnRedisSentinelNodes(replicasCount: number) {
+    const master = await this.#testUtils.spawnRedisServer({serverArguments: DEBUG_MODE_ARGS})
+    
+    const replicas: Array<RedisServerDocker> = []
+    for (let i = 0; i < replicasCount; i++) {
+      const replica = await this.#testUtils.spawnRedisServer({serverArguments: DEBUG_MODE_ARGS})
+      replicas.push(replica)
 
-    const promises: Array<ReturnType<SentinelFramework['spawnRedisSentinelNodeDocker']>> = [];
+      const client = RedisClient.create({
+        socket: {
+          port: replica.port
+        }
+      })
 
-    for (let i = 0; i < (this.config.numberOfNodes ?? 0) - 1; i++) {
-      promises.push(
-        this.spawnRedisSentinelNodeDocker().then(async node => {
-          if (this.config.password !== undefined) {
-            await node.client.configSet({'masterauth': this.config.password})
-          }
-          await node.client.replicaOf('127.0.0.1', master.docker.port);
-          return node;
-        })
-      );
+      await client.connect();
+      await client.replicaOf("127.0.0.1", master.port);
+      await client.close();
     }
 
     return [
       master,
-      ...await Promise.all(promises)
-    ];
-  }
-
-  protected async spawnRedisSentinelSentinelDocker() {
-    const imageInfo: RedisServerDockerConfig = this.config.sentinelDockerConfig ?? { image: "redis", version: "latest" }
-    let serverArguments: Array<string>;
-    if (this.config.password === undefined) {
-      serverArguments = this.config.sentinelServerArgument ??
-        [
-          "/bin/bash",
-          "-c",
-          "\"touch /tmp/sentinel.conf ; /usr/local/bin/redis-sentinel /tmp/sentinel.conf {port} \""
-        ];
-    } else {
-      serverArguments = this.config.sentinelServerArgument ??
-        [
-          "/bin/bash",
-          "-c",
-          `"touch /tmp/sentinel.conf ; /usr/local/bin/redis-sentinel /tmp/sentinel.conf {port} --requirepass ${this.config.password}"`
-        ];
-    }
-    
-    const docker = await this.spawnRedisServerDocker(imageInfo, serverArguments);
-    const client = await RedisClient.create({
-      modules: RedisSentinelModule,
-      password: this.config.password,
-      socket: {
-        port: docker.port
-      }
-    }).on("error", () => { }).connect();
-
-    return {
-      docker,
-      client
-    };
+      ...replicas
+    ]
   }
 
-  protected async spawnRedisSentinelSentinels() {
-    const quorum = this.config.sentinelQuorum?.toString() ?? "2";
-    const node = this.#nodeList[0];
-
-    const promises: Array<ReturnType<SentinelFramework['spawnRedisSentinelSentinelDocker']>> = [];
-
-    for (let i = 0; i < (this.config.numberOfSentinels ?? 3); i++) {
-      promises.push(
-        this.spawnRedisSentinelSentinelDocker().then(async sentinel => {
-          await sentinel.client.sentinel.sentinelMonitor(this.config.sentinelName, '127.0.0.1', node.docker.port.toString(), quorum);
-          const options: Array<{option: RedisArgument, value: RedisArgument}> = [];
-          options.push({ option: "down-after-milliseconds", value: "100" });
-          options.push({ option: "failover-timeout", value: "5000" });
-          if (this.config.password !== undefined) {
-            options.push({ option: "auth-pass", value: this.config.password });
-          }
-          await sentinel.client.sentinel.sentinelSet(this.config.sentinelName, options)
-          return sentinel;
-        })
-      );
-    }
-
-    return [
-      ...await Promise.all(promises)
-    ]
+  protected async spawnRedisSentinelSentinels(masterPort: number, sentinels: number) {
+    return this.#testUtils.spawnRedisSentinels({serverArguments: DEBUG_MODE_ARGS}, masterPort, this.config.sentinelName, sentinels)
   }
 
   async getAllRunning() {
@@ -384,90 +307,71 @@ export class SentinelFramework extends DockerBase {
   }
 
   async addSentinel() {
-    const quorum = this.config.sentinelQuorum?.toString() ?? "2";
-    const node = this.#nodeList[0];
-    const sentinel = await this.spawnRedisSentinelSentinelDocker();
-
-    await sentinel.client.sentinel.sentinelMonitor(this.config.sentinelName, '127.0.0.1', node.docker.port.toString(), quorum);
-    const options: Array<{option: RedisArgument, value: RedisArgument}> = [];
-    options.push({ option: "down-after-milliseconds", value: "100" });
-    options.push({ option: "failover-timeout", value: "5000" });
-    if (this.config.password !== undefined) {
-      options.push({ option: "auth-pass", value: this.config.password });
-    }
-    await sentinel.client.sentinel.sentinelSet(this.config.sentinelName, options);
-
-    this.#sentinelList.push(sentinel);
-    this.#sentinelMap.set(sentinel.docker.port.toString(), sentinel);
+    const nodes = await this.#testUtils.spawnRedisSentinels({serverArguments: DEBUG_MODE_ARGS}, this.#nodeList[0].port, this.config.sentinelName, 1)
+    this.#sentinelList.push(nodes[0]);
+    this.#sentinelMap.set(nodes[0].port.toString(), nodes[0]);
   }
 
   async addNode() {
     const masterPort = await this.getMasterPort();
-    const newNode = await this.spawnRedisSentinelNodeDocker();
+    const replica = await this.#testUtils.spawnRedisServer({serverArguments: DEBUG_MODE_ARGS})
 
-    if (this.config.password !== undefined) {
-      await newNode.client.configSet({'masterauth': this.config.password})
-    }
-    await newNode.client.replicaOf('127.0.0.1', masterPort);
+    const client = RedisClient.create({
+      socket: {
+        port: replica.port
+      }
+    })
+
+    await client.connect();
+    await client.replicaOf("127.0.0.1", masterPort);
+    await client.close();
+    
 
-    this.#nodeList.push(newNode);
-    this.#nodeMap.set(newNode.docker.port.toString(), newNode);
+    this.#nodeList.push(replica);
+    this.#nodeMap.set(replica.port.toString(), replica);
   }
 
   async getMaster(tracer?: Array<string>): Promise<string | undefined> {
-    for (const sentinel of this.#sentinelMap!.values()) {
-      let info;
-
-      try {
-        if (!sentinel.client.isReady) {
-          continue;
-        }
-
-        info = await sentinel.client.sentinel.sentinelMaster(this.config.sentinelName);
-        if (tracer) {
-          tracer.push('getMaster: master data returned from sentinel');
-          tracer.push(JSON.stringify(info, undefined, '\t'))
-        }
-      } catch (err) {
-        console.log("getMaster: sentinelMaster call failed: " + err);
-        continue;
-      }
-
-      const master = this.#nodeMap.get(info.port); 
-      if (master === undefined) {
-        throw new Error(`couldn't find master node for ${info.port}`);
-      }
-
-      if (tracer) {
-        tracer.push(`getMaster: master port is either ${info.port} or ${master.docker.port}`);
-      }
+    const client = RedisClient.create({
+      name: this.config.sentinelName, 
+      socket: {
+        host: "127.0.0.1", 
+        port: this.#sentinelList[0].port,
+      },
+      modules: RedisSentinelModule,
+    });
+    await client.connect()
+    const info = await client.sentinel.sentinelMaster(this.config.sentinelName);
+    await client.close()
 
-      if (!master.client.isOpen) {
-        throw new Error(`Sentinel's expected master node (${info.port}) is now down`);
-      }
+    const master = this.#nodeMap.get(info.port);
+    if (master === undefined) {
+      throw new Error(`couldn't find master node for ${info.port}`);
+    }
 
-      return info.port;
+    if (tracer) {
+      tracer.push(`getMaster: master port is either ${info.port} or ${master.port}`);
     }
 
-    throw new Error("Couldn't get master");
+    return info.port;
   }
 
   async getMasterPort(tracer?: Array<string>): Promise<number> {
     const data = await this.getMaster(tracer)
 
-    return this.#nodeMap.get(data!)!.docker.port;
+    return this.#nodeMap.get(data!)!.port;
   }
 
   getRandomNode() {
-    return this.#nodeList[Math.floor(Math.random() * this.#nodeList.length)].docker.port.toString();
+    return this.#nodeList[Math.floor(Math.random() * this.#nodeList.length)].port.toString();
   }
 
   async getRandonNonMasterNode(): Promise<string> {
     const masterPort = await this.getMasterPort();
     while (true) {
       const node = this.#nodeList[Math.floor(Math.random() * this.#nodeList.length)];
-      if (node.docker.port != masterPort) {
-        return node.docker.port.toString();
+      if (node.port != masterPort) {
+        return node.port.toString();
       }
     }
   }
@@ -479,11 +383,7 @@ export class SentinelFramework extends DockerBase {
       throw new Error("unknown node: " + id);
     }
 
-    if (node.client.isOpen) {
-      node.client.destroy();
-    }
-
-    return await this.dockerStop(node.docker.dockerId);
+    return await this.dockerStop(node.dockerId);
   }
 
   async restartNode(id: string) {
@@ -492,15 +392,7 @@ export class SentinelFramework extends DockerBase {
       throw new Error("unknown node: " + id);
     }
 
-    await this.dockerStart(node.docker.dockerId);
-    if (!node.client.isOpen) {
-      node.client = await RedisClient.create({
-        password: this.config.password,
-        socket: {
-          port: node.docker.port
-        }
-      }).on("error", () => { }).connect();
-    }
+    await this.dockerStart(node.dockerId);
   }
 
   async stopSentinel(id: string) {
@@ -509,11 +401,7 @@ export class SentinelFramework extends DockerBase {
       throw new Error("unknown sentinel: " + id);
     }
 
-    if (sentinel.client.isOpen) {
-      sentinel.client.destroy();
-    }
-
-    return await this.dockerStop(sentinel.docker.dockerId);
+    return await this.dockerStop(sentinel.dockerId);
   }
 
   async restartSentinel(id: string) {
@@ -522,16 +410,7 @@ export class SentinelFramework extends DockerBase {
       throw new Error("unknown sentinel: " + id);
     }
 
-    await this.dockerStart(sentinel.docker.dockerId);
-    if (!sentinel.client.isOpen) {
-      sentinel.client = await RedisClient.create({
-        modules: RedisSentinelModule,
-        password: this.config.password,
-        socket: {
-          port: sentinel.docker.port
-        }
-      }).on("error", () => { }).connect();
-    }
+    await this.dockerStart(sentinel.dockerId);
   }
 
   getNodePort(id: string) {
@@ -540,13 +419,13 @@ export class SentinelFramework extends DockerBase {
       throw new Error("unknown node: " + id);
     }
 
-    return node.docker.port;
+    return node.port;
   }
 
   getAllNodesPort() {
     let ports: Array<number> = [];
     for (const node of this.#nodeList) {
-      ports.push(node.docker.port);
+      ports.push(node.port);
     }
 
     return ports
@@ -555,7 +434,7 @@ export class SentinelFramework extends DockerBase {
   getAllDockerIds() {
     let ids = new Map<string, number>();
     for (const node of this.#nodeList) {
-      ids.set(node.docker.dockerId, node.docker.port);
+      ids.set(node.dockerId, node.port);
     }
 
     return ids;
@@ -567,43 +446,67 @@ export class SentinelFramework extends DockerBase {
       throw new Error("unknown sentinel: " + id);
     }
 
-    return sentinel.docker.port;
+    return sentinel.port;
   }
 
   getAllSentinelsPort() {
     let ports: Array<number> = [];
     for (const sentinel of this.#sentinelList) {
-      ports.push(sentinel.docker.port);
+      ports.push(sentinel.port);
     }
 
     return ports
   }
 
   getSetinel(i: number): string {
-    return this.#sentinelList[i].docker.port.toString();
+    return this.#sentinelList[i].port.toString();
   }
 
-  sentinelSentinels() {
-    for (const sentinel of this.#sentinelList) {
-      if (sentinel.client.isReady) {
-        return sentinel.client.sentinel.sentinelSentinels(this.config.sentinelName);
-      }
-    }
+  async sentinelSentinels() {
+    const client = RedisClient.create({
+      name: this.config.sentinelName, 
+      socket: {
+        host: "127.0.0.1", 
+        port: this.#sentinelList[0].port,
+      },
+      modules: RedisSentinelModule,
+    });
+    await client.connect()
+    const sentinels = client.sentinel.sentinelSentinels(this.config.sentinelName)
+    await client.close()
+
+    return sentinels
   }
 
-  sentinelMaster() {
-    for (const sentinel of this.#sentinelList) {
-      if (sentinel.client.isReady) {
-        return sentinel.client.sentinel.sentinelMaster(this.config.sentinelName);
-      }
-    }
+  async sentinelMaster() {
+    const client = RedisClient.create({
+      name: this.config.sentinelName, 
+      socket: {
+        host: "127.0.0.1", 
+        port: this.#sentinelList[0].port,
+      },
+      modules: RedisSentinelModule,
+    });
+    await client.connect()
+    const master = client.sentinel.sentinelMaster(this.config.sentinelName)
+    await client.close()
+
+    return master
   }
 
-  sentinelReplicas() {
-    for (const sentinel of this.#sentinelList) {
-      if (sentinel.client.isReady) {
-        return sentinel.client.sentinel.sentinelReplicas(this.config.sentinelName);
-      }
-    }
+  async sentinelReplicas() {
+    const client = RedisClient.create({
+      name: this.config.sentinelName, 
+      socket: {
+        host: "127.0.0.1", 
+        port: this.#sentinelList[0].port,
+      },
+      modules: RedisSentinelModule,
+    });
+    await client.connect()
+    const replicas = client.sentinel.sentinelReplicas(this.config.sentinelName)
+    await client.close()
+
+    return replicas
   }
 }
\ No newline at end of file
diff --git a/packages/client/lib/test-utils.ts b/packages/client/lib/test-utils.ts
index 63f43ba5e6..19bbafc66e 100644
--- a/packages/client/lib/test-utils.ts
+++ b/packages/client/lib/test-utils.ts
@@ -14,7 +14,7 @@ const utils = TestUtils.createFromConfig({
 
 export default utils;
 
-const DEBUG_MODE_ARGS = utils.isVersionGreaterThan([7]) ?
+export const DEBUG_MODE_ARGS = utils.isVersionGreaterThan([7]) ?
   ['--enable-debug-command', 'yes'] :
   [];
 
diff --git a/packages/client/package.json b/packages/client/package.json
index dd41dc53e0..a6d44451a6 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/client",
-  "version": "5.1.0",
+  "version": "5.1.1",
   "license": "MIT",
   "main": "./dist/index.js",
   "types": "./dist/index.d.ts",
diff --git a/packages/entraid/package.json b/packages/entraid/package.json
index ba44351b3b..43f26d1e03 100644
--- a/packages/entraid/package.json
+++ b/packages/entraid/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/entraid",
-  "version": "5.1.0",
+  "version": "5.1.1",
   "license": "MIT",
   "main": "./dist/index.js",
   "types": "./dist/index.d.ts",
@@ -21,7 +21,7 @@
     "@azure/msal-node": "^2.16.1"
   },
   "peerDependencies": {
-    "@redis/client": "^5.1.0"
+    "@redis/client": "^5.1.1"
   },
   "devDependencies": {
     "@types/express": "^4.17.21",
diff --git a/packages/json/lib/commands/helpers.ts b/packages/json/lib/commands/helpers.ts
index 26ff12f683..99579ce81c 100644
--- a/packages/json/lib/commands/helpers.ts
+++ b/packages/json/lib/commands/helpers.ts
@@ -2,7 +2,6 @@ import { isNullReply } from "@redis/client/dist/lib/commands/generic-transformer
 import { BlobStringReply, NullReply, UnwrapReply } from "@redis/client/dist/lib/RESP/types";
 
 export function transformRedisJsonNullReply(json: NullReply | BlobStringReply): NullReply | RedisJSON {
-  console.log('transformRedisJsonNullReply', json)
   return isNullReply(json) ? json : transformRedisJsonReply(json);
 }
 
@@ -17,6 +16,5 @@ export function transformRedisJsonArgument(json: RedisJSON): string {
 
 export function transformRedisJsonReply(json: BlobStringReply): RedisJSON {
   const res =  JSON.parse((json as unknown as UnwrapReply<typeof json>).toString());
-  console.log('transformRedisJsonReply', json, res)
   return res;
 }
diff --git a/packages/json/package.json b/packages/json/package.json
index fd0b3c768f..3b473dfce0 100644
--- a/packages/json/package.json
+++ b/packages/json/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/json",
-  "version": "5.1.0",
+  "version": "5.1.1",
   "license": "MIT",
   "main": "./dist/lib/index.js",
   "types": "./dist/lib/index.d.ts",
@@ -12,7 +12,7 @@
     "test": "nyc -r text-summary -r lcov mocha -r tsx './lib/**/*.spec.ts'"
   },
   "peerDependencies": {
-    "@redis/client": "^5.1.0"
+    "@redis/client": "^5.1.1"
   },
   "devDependencies": {
     "@redis/test-utils": "*"
diff --git a/packages/redis/README.md b/packages/redis/README.md
index d04a19b0d7..ab6b4707e6 100644
--- a/packages/redis/README.md
+++ b/packages/redis/README.md
@@ -45,13 +45,13 @@ npm install redis
 
 | Name                                           | Description                                                                                 |
 | ---------------------------------------------- | ------------------------------------------------------------------------------------------- |
-| [`redis`](../redis)                    | The client with all the ["redis-stack"](https://github.com/redis-stack/redis-stack) modules |
-| [`@redis/client`](../client)           | The base clients (i.e `RedisClient`, `RedisCluster`, etc.)                                  |
-| [`@redis/bloom`](../bloom)             | [Redis Bloom](https://redis.io/docs/data-types/probabilistic/) commands                     |
-| [`@redis/json`](../json)               | [Redis JSON](https://redis.io/docs/data-types/json/) commands                               |
-| [`@redis/search`](../search)           | [RediSearch](https://redis.io/docs/interact/search-and-query/) commands                     |
-| [`@redis/time-series`](../time-series) | [Redis Time-Series](https://redis.io/docs/data-types/timeseries/) commands                  |
-| [`@redis/entraid`](../entraid)         | Secure token-based authentication for Redis clients using Microsoft Entra ID                |
+| [`redis`](https://github.com/redis/node-redis/tree/master/packages/redis)                    | The client with all the ["redis-stack"](https://github.com/redis-stack/redis-stack) modules |
+| [`@redis/client`](https://github.com/redis/node-redis/tree/master/packages/client)           | The base clients (i.e `RedisClient`, `RedisCluster`, etc.)                                  |
+| [`@redis/bloom`](https://github.com/redis/node-redis/tree/master/packages/bloom)             | [Redis Bloom](https://redis.io/docs/data-types/probabilistic/) commands                     |
+| [`@redis/json`](https://github.com/redis/node-redis/tree/master/packages/json)               | [Redis JSON](https://redis.io/docs/data-types/json/) commands                               |
+| [`@redis/search`](https://github.com/redis/node-redis/tree/master/packages/search)           | [RediSearch](https://redis.io/docs/interact/search-and-query/) commands                     |
+| [`@redis/time-series`](https://github.com/redis/node-redis/tree/master/packages/time-series) | [Redis Time-Series](https://redis.io/docs/data-types/timeseries/) commands                  |
+| [`@redis/entraid`](https://github.com/redis/node-redis/tree/master/packages/entraid)         | Secure token-based authentication for Redis clients using Microsoft Entra ID                |
 
 > Looking for a high-level library to handle object mapping?
 > See [redis-om-node](https://github.com/redis/redis-om-node)!
@@ -83,7 +83,7 @@ createClient({
 ```
 
 You can also use discrete parameters, UNIX sockets, and even TLS to connect. Details can be found in
-the [client configuration guide](../../docs/client-configuration.md).
+the [client configuration guide](https://github.com/redis/node-redis/blob/master/docs/client-configuration.md).
 
 To check if the the client is connected and ready to send commands, use `client.isReady` which returns a boolean.
 `client.isOpen` is also available. This returns `true` when the client's underlying socket is open, and `false` when it
@@ -188,7 +188,7 @@ await pool.ping();
 
 ### Pub/Sub
 
-See the [Pub/Sub overview](../../docs/pub-sub.md).
+See the [Pub/Sub overview](https://github.com/redis/node-redis/blob/master/docs/pub-sub.md).
 
 ### Scan Iterator
 
@@ -250,7 +250,7 @@ const client = createClient({
 });
 ```
 
-See the [V5 documentation](../../docs/v5.md#client-side-caching) for more details and advanced usage.
+See the [V5 documentation](https://github.com/redis/node-redis/blob/master/docs/v5.md#client-side-caching) for more details and advanced usage.
 
 ### Auto-Pipelining
 
@@ -274,11 +274,11 @@ await Promise.all([
 
 ### Programmability
 
-See the [Programmability overview](../../docs/programmability.md).
+See the [Programmability overview](https://github.com/redis/node-redis/blob/master/docs/programmability.md).
 
 ### Clustering
 
-Check out the [Clustering Guide](../../docs/clustering.md) when using Node Redis to connect to a Redis Cluster.
+Check out the [Clustering Guide](https://github.com/redis/node-redis/blob/master/docs/clustering.md) when using Node Redis to connect to a Redis Cluster.
 
 ### Events
 
@@ -291,12 +291,12 @@ The Node Redis client class is an Nodejs EventEmitter and it emits an event each
 | `end`                   | Connection has been closed (via `.disconnect()`)                                   | _No arguments_                                            |
 | `error`                 | An error has occurred—usually a network issue such as "Socket closed unexpectedly" | `(error: Error)`                                          |
 | `reconnecting`          | Client is trying to reconnect to the server                                        | _No arguments_                                            |
-| `sharded-channel-moved` | See [here](../../docs/pub-sub.md#sharded-channel-moved-event)                          | See [here](../../docs/pub-sub.md#sharded-channel-moved-event) |
+| `sharded-channel-moved` | See [here](https://github.com/redis/node-redis/blob/master/docs/pub-sub.md#sharded-channel-moved-event)                          | See [here](https://github.com/redis/node-redis/blob/master/docs/pub-sub.md#sharded-channel-moved-event) |
 
 > :warning: You **MUST** listen to `error` events. If a client doesn't have at least one `error` listener registered and
 > an `error` occurs, that error will be thrown and the Node.js process will exit. See the [ > `EventEmitter` docs](https://nodejs.org/api/events.html#events_error_events) for more details.
 
-> The client will not emit [any other events](../../docs/v3-to-v4.md#all-the-removed-events) beyond those listed above.
+> The client will not emit [any other events](https://github.com/redis/node-redis/blob/master/docs/v3-to-v4.md#all-the-removed-events) beyond those listed above.
 
 ## Supported Redis versions
 
@@ -313,13 +313,13 @@ Node Redis is supported with the following versions of Redis:
 
 ## Migration
 
-- [From V3 to V4](../../docs/v3-to-v4.md)
-- [From V4 to V5](../../docs/v4-to-v5.md)
-- [V5](../../docs/v5.md)
+- [From V3 to V4](https://github.com/redis/node-redis/blob/master/docs/v3-to-v4.md)
+- [From V4 to V5](https://github.com/redis/node-redis/blob/master/docs/v4-to-v5.md)
+- [V5](https://github.com/redis/node-redis/blob/master/docs/v5.md)
 
 ## Contributing
 
-If you'd like to contribute, check out the [contributing guide](../../CONTRIBUTING.md).
+If you'd like to contribute, check out the [contributing guide](https://github.com/redis/node-redis/blob/master/CONTRIBUTING.md).
 
 Thank you to all the people who already contributed to Node Redis!
 
@@ -327,4 +327,4 @@ Thank you to all the people who already contributed to Node Redis!
 
 ## License
 
-This repository is licensed under the "MIT" license. See [LICENSE](../../LICENSE).
+This repository is licensed under the "MIT" license. See [LICENSE](https://github.com/redis/node-redis/blob/master/LICENSE).
diff --git a/packages/redis/package.json b/packages/redis/package.json
index e7c9da2660..b6c3f409a6 100644
--- a/packages/redis/package.json
+++ b/packages/redis/package.json
@@ -1,7 +1,7 @@
 {
   "name": "redis",
   "description": "A modern, high performance Redis client",
-  "version": "5.0.1",
+  "version": "5.1.0",
   "license": "MIT",
   "main": "./dist/index.js",
   "types": "./dist/index.d.ts",
@@ -10,11 +10,11 @@
     "!dist/tsconfig.tsbuildinfo"
   ],
   "dependencies": {
-    "@redis/bloom": "5.0.1",
-    "@redis/client": "5.0.1",
-    "@redis/json": "5.0.1",
-    "@redis/search": "5.0.1",
-    "@redis/time-series": "5.0.1"
+    "@redis/bloom": "5.1.0",
+    "@redis/client": "5.1.0",
+    "@redis/json": "5.1.0",
+    "@redis/search": "5.1.0",
+    "@redis/time-series": "5.1.0"
   },
   "engines": {
     "node": ">= 18"
diff --git a/packages/search/package.json b/packages/search/package.json
index ba1fa2a74b..ac56b5ff5d 100644
--- a/packages/search/package.json
+++ b/packages/search/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/search",
-  "version": "5.0.1",
+  "version": "5.1.0",
   "license": "MIT",
   "main": "./dist/lib/index.js",
   "types": "./dist/lib/index.d.ts",
@@ -13,7 +13,7 @@
     "test-sourcemap": "mocha -r ts-node/register/transpile-only './lib/**/*.spec.ts'"
   },
   "peerDependencies": {
-    "@redis/client": "^5.0.1"
+    "@redis/client": "^5.1.0"
   },
   "devDependencies": {
     "@redis/test-utils": "*"
diff --git a/packages/test-utils/lib/dockers.ts b/packages/test-utils/lib/dockers.ts
index 3814a80923..47257964f6 100644
--- a/packages/test-utils/lib/dockers.ts
+++ b/packages/test-utils/lib/dockers.ts
@@ -62,7 +62,7 @@ export interface RedisServerDocker {
   dockerId: string;
 }
 
-async function spawnRedisServerDocker(
+export async function spawnRedisServerDocker(
 options: RedisServerDockerOptions, serverArguments: Array<string>): Promise<RedisServerDocker> {
   let port;
   if (options.mode == "sentinel") {
@@ -374,35 +374,16 @@ export async function spawnRedisSentinel(
     const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), appPrefix));
 
     for (let i = 0; i < sentinelCount; i++) {
-      sentinelPromises.push((async () => {
-        const port = (await portIterator.next()).value;
-
-        let sentinelConfig = `port ${port}
-sentinel monitor mymaster 127.0.0.1 ${master.port} 2
-sentinel down-after-milliseconds mymaster 5000
-sentinel failover-timeout mymaster 6000
-`;
-        if (password !== undefined) {
-          sentinelConfig += `requirepass ${password}\n`;
-          sentinelConfig += `sentinel auth-pass mymaster ${password}\n`;
-        }
-
-        const dir = fs.mkdtempSync(path.join(tmpDir, i.toString()));
-        fs.writeFile(`${dir}/redis.conf`, sentinelConfig, err => {
-          if (err) {
-            console.error("failed to create temporary config file", err);
-          }
-        });
-
-        return await spawnRedisServerDocker(
-          {
-            image: dockerConfigs.image, 
-            version: dockerConfigs.version, 
-            mode: "sentinel",
-             mounts: [`${dir}/redis.conf:/redis/config/node-sentinel-1/redis.conf`], 
-             port: port,
-            }, serverArguments);
-      })());
+      sentinelPromises.push(
+        spawnSentinelNode(
+          dockerConfigs, 
+          serverArguments, 
+          master.port,
+          "mymaster",
+          path.join(tmpDir, i.toString()),
+          password,
+        ),
+      )
     }
     
     const sentinelNodes = await Promise.all(sentinelPromises);
@@ -424,3 +405,43 @@ after(() => {
     })
   );
 });
+
+
+export async function spawnSentinelNode(
+  dockerConfigs: RedisServerDockerOptions,
+  serverArguments: Array<string>,
+  masterPort: number, 
+  sentinelName: string,
+  tmpDir: string,
+  password?: string,
+) {
+  const port = (await portIterator.next()).value;
+
+  let sentinelConfig = `port ${port}
+sentinel monitor ${sentinelName} 127.0.0.1 ${masterPort} 2
+sentinel down-after-milliseconds ${sentinelName} 500
+sentinel failover-timeout ${sentinelName} 1000
+`;
+  if (password !== undefined) {
+    sentinelConfig += `requirepass ${password}\n`;
+    sentinelConfig += `sentinel auth-pass ${sentinelName} ${password}\n`;
+  }
+
+  const dir = fs.mkdtempSync(tmpDir);
+  fs.writeFile(`${dir}/redis.conf`, sentinelConfig, err => {
+    if (err) {
+      console.error("failed to create temporary config file", err);
+    }
+  });
+
+  return await spawnRedisServerDocker(
+    {
+      image: dockerConfigs.image, 
+      version: dockerConfigs.version, 
+      mode: "sentinel",
+        mounts: [`${dir}/redis.conf:/redis/config/node-sentinel-1/redis.conf`], 
+        port: port,
+    }, 
+    serverArguments,
+  );
+}
\ No newline at end of file
diff --git a/packages/test-utils/lib/index.ts b/packages/test-utils/lib/index.ts
index d92c5c9e3d..a41f970e0c 100644
--- a/packages/test-utils/lib/index.ts
+++ b/packages/test-utils/lib/index.ts
@@ -19,10 +19,13 @@ import {
   RedisClusterType
 } from '@redis/client/index';
 import { RedisNode } from '@redis/client/lib/sentinel/types'
-import { spawnRedisServer, spawnRedisCluster, spawnRedisSentinel, RedisServerDockerOptions } from './dockers';
+import { spawnRedisServer, spawnRedisCluster, spawnRedisSentinel, RedisServerDockerOptions, RedisServerDocker, spawnSentinelNode, spawnRedisServerDocker } from './dockers';
 import yargs from 'yargs';
 import { hideBin } from 'yargs/helpers';
 
+import * as fs from 'node:fs';
+import * as os from 'node:os';
+import * as path from 'node:path';
 
 interface TestUtilsConfig {
   /**
@@ -395,19 +398,19 @@ export default class TestUtils {
   S extends RedisScripts = {},
   RESP extends RespVersions = 2,
   TYPE_MAPPING extends TypeMapping = {}
->(
-  range: ([minVersion: Array<number>, maxVersion: Array<number>] | [minVersion: Array<number>, 'LATEST']),
-  title: string,
-  fn: (sentinel: RedisSentinelType<M, F, S, RESP, TYPE_MAPPING>) => unknown,
-  options: SentinelTestOptions<M, F, S, RESP, TYPE_MAPPING>
-): void {
-
-  if (this.isVersionInRange(range[0], range[1] === 'LATEST' ? [Infinity, Infinity, Infinity] : range[1])) {
-    return this.testWithClientSentinel(`${title}  [${range[0].join('.')}] - [${(range[1] === 'LATEST') ? range[1] : range[1].join(".")}] `, fn, options)
-  } else {
-    console.warn(`Skipping test ${title} because server version ${this.#VERSION_NUMBERS.join('.')} is not within range ${range[0].join(".")} - ${range[1] !== 'LATEST' ? range[1].join(".") : 'LATEST'}`)
+  >(
+    range: ([minVersion: Array<number>, maxVersion: Array<number>] | [minVersion: Array<number>, 'LATEST']),
+    title: string,
+    fn: (sentinel: RedisSentinelType<M, F, S, RESP, TYPE_MAPPING>) => unknown,
+    options: SentinelTestOptions<M, F, S, RESP, TYPE_MAPPING>
+  ): void {
+
+    if (this.isVersionInRange(range[0], range[1] === 'LATEST' ? [Infinity, Infinity, Infinity] : range[1])) {
+      return this.testWithClientSentinel(`${title}  [${range[0].join('.')}] - [${(range[1] === 'LATEST') ? range[1] : range[1].join(".")}] `, fn, options)
+    } else {
+      console.warn(`Skipping test ${title} because server version ${this.#VERSION_NUMBERS.join('.')} is not within range ${range[0].join(".")} - ${range[1] !== 'LATEST' ? range[1].join(".") : 'LATEST'}`)
+    }
   }
-}
 
   testWithClientPool<
     M extends RedisModules = {},
@@ -541,4 +544,46 @@ export default class TestUtils {
     this.testWithClient(`client.${title}`, fn, options.client);
     this.testWithCluster(`cluster.${title}`, fn, options.cluster);
   }
+
+
+  spawnRedisServer<
+    M extends RedisModules = {},
+    F extends RedisFunctions = {},
+    S extends RedisScripts = {},
+    RESP extends RespVersions = 2,
+    TYPE_MAPPING extends TypeMapping = {}
+    // POLICIES extends CommandPolicies = {}
+  >(
+    options: ClientPoolTestOptions<M, F, S, RESP, TYPE_MAPPING>
+  ): Promise<RedisServerDocker> {
+    return spawnRedisServerDocker(this.#DOCKER_IMAGE, options.serverArguments)
+  }
+
+  async spawnRedisSentinels<
+    M extends RedisModules = {},
+    F extends RedisFunctions = {},
+    S extends RedisScripts = {},
+    RESP extends RespVersions = 2,
+    TYPE_MAPPING extends TypeMapping = {}
+    // POLICIES extends CommandPolicies = {}
+  >(
+    options: ClientPoolTestOptions<M, F, S, RESP, TYPE_MAPPING>,
+    masterPort: number,
+    sentinelName: string,
+    count: number
+  ): Promise<Array<RedisServerDocker>> {
+    const sentinels: Array<RedisServerDocker> = [];
+    for (let i = 0; i < count; i++) {
+      const appPrefix = 'sentinel-config-dir';
+      const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), appPrefix));
+
+      sentinels.push(await spawnSentinelNode(this.#DOCKER_IMAGE, options.serverArguments, masterPort, sentinelName, tmpDir))
+      
+      if (tmpDir) {
+        fs.rmSync(tmpDir, { recursive: true });
+      }
+    }
+    
+    return sentinels
+  }
 }
diff --git a/packages/time-series/package.json b/packages/time-series/package.json
index 1b436701d6..466c53df22 100644
--- a/packages/time-series/package.json
+++ b/packages/time-series/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@redis/time-series",
-  "version": "5.0.1",
+  "version": "5.1.0",
   "license": "MIT",
   "main": "./dist/lib/index.js",
   "types": "./dist/lib/index.d.ts",
@@ -12,7 +12,7 @@
     "test": "nyc -r text-summary -r lcov mocha -r tsx './lib/**/*.spec.ts'"
   },
   "peerDependencies": {
-    "@redis/client": "^5.0.1"
+    "@redis/client": "^5.1.0"
   },
   "devDependencies": {
     "@redis/test-utils": "*"