diff --git a/README.md b/README.md
index 6652011..94416ff 100644
--- a/README.md
+++ b/README.md
@@ -46,6 +46,7 @@ It enables you to set and query its data or use its PubSub topics to react to in
 * [API](#api)
     * [RedisClient](#redisclient)
         * [__construct()](#__construct)
+        * [__clone()](#__clone)
         * [__call()](#__call)
         * [callAsync()](#callasync)
         * [end()](#end)
@@ -415,6 +416,42 @@ $connector = new React\Socket\Connector([
 $redis = new Clue\React\Redis\RedisClient('localhost', $connector);
 ```
 
+#### __clone()
+
+The `__clone()` method is a magic method in PHP that is called
+automatically when a `RedisClient` instance is being cloned:
+
+```php
+$original = new Clue\React\Redis\RedisClient($uri);
+$redis = clone $original;
+```
+
+This method ensures the cloned client is created in a "fresh" state and
+any connection state is reset on the clone, matching how a new instance
+would start after returning from its constructor. Accordingly, the clone
+will always start in an unconnected and unclosed state, with no event
+listeners attached and ready to accept commands. Invoking any of the
+[commands](#commands) will establish a new connection as usual:
+
+```php
+$redis = clone $original;
+$redis->set('name', 'Alice');
+```
+
+This can be especially useful if the original connection is used for a
+[PubSub subscription](#pubsub) or when using blocking commands or similar
+and you need a control connection that is not affected by any of this.
+Both instances will not be directly affected by any operations performed,
+for example you can [`close()`](#close) either instance without also
+closing the other. Similarly, you can also clone a fresh instance from a
+closed state or overwrite a dead connection:
+
+```php
+$redis->close();
+$redis = clone $redis;
+$redis->set('name', 'Alice');
+```
+
 #### __call()
 
 The `__call(string $name, list<string|int|float> $args): PromiseInterface<mixed>` method can be used to
diff --git a/src/RedisClient.php b/src/RedisClient.php
index 32ced43..1c1bf87 100644
--- a/src/RedisClient.php
+++ b/src/RedisClient.php
@@ -90,6 +90,55 @@ public function __construct(string $uri, ?ConnectorInterface $connector = null)
         $this->factory = new Factory($connector);
     }
 
+    /**
+     * The `__clone()` method is a magic method in PHP that is called
+     * automatically when a `RedisClient` instance is being cloned:
+     *
+     * ```php
+     * $original = new Clue\React\Redis\RedisClient($uri);
+     * $redis = clone $original;
+     * ```
+     *
+     * This method ensures the cloned client is created in a "fresh" state and
+     * any connection state is reset on the clone, matching how a new instance
+     * would start after returning from its constructor. Accordingly, the clone
+     * will always start in an unconnected and unclosed state, with no event
+     * listeners attached and ready to accept commands. Invoking any of the
+     * [commands](#commands) will establish a new connection as usual:
+     *
+     * ```php
+     * $redis = clone $original;
+     * $redis->set('name', 'Alice');
+     * ```
+     *
+     * This can be especially useful if the original connection is used for a
+     * [PubSub subscription](#pubsub) or when using blocking commands or similar
+     * and you need a control connection that is not affected by any of this.
+     * Both instances will not be directly affected by any operations performed,
+     * for example you can [`close()`](#close) either instance without also
+     * closing the other. Similarly, you can also clone a fresh instance from a
+     * closed state or overwrite a dead connection:
+     *
+     * ```php
+     * $redis->close();
+     * $redis = clone $redis;
+     * $redis->set('name', 'Alice');
+     * ```
+     *
+     * @return void
+     * @throws void
+     */
+    public function __clone()
+    {
+        $this->closed = false;
+        $this->promise = null;
+        $this->idleTimer = null;
+        $this->pending = 0;
+        $this->subscribed = [];
+        $this->psubscribed = [];
+        $this->removeAllListeners();
+    }
+
     /**
      * @return PromiseInterface<StreamingClient>
      */
diff --git a/tests/FunctionalTest.php b/tests/FunctionalTest.php
index 25bf829..5757eac 100644
--- a/tests/FunctionalTest.php
+++ b/tests/FunctionalTest.php
@@ -176,4 +176,46 @@ public function testClose(): void
 
         $redis->get('willBeRejectedRightAway')->then(null, $this->expectCallableOnce());
     }
+
+    public function testCloneWhenOriginalIsIdleReturnsClientThatWillCloseIndependently(): void
+    {
+        $prefix = 'test:' . mt_rand() . ':';
+        $original = new RedisClient($this->uri);
+
+        $this->assertNull(await($original->callAsync('GET', $prefix . 'doesnotexist')));
+
+        $redis = clone $original;
+
+        $this->assertNull(await($redis->callAsync('GET', $prefix . 'doesnotexist')));
+    }
+
+    public function testCloneWhenOriginalIsPendingReturnsClientThatWillCloseIndependently(): void
+    {
+        $prefix = 'test:' . mt_rand() . ':';
+        $original = new RedisClient($this->uri);
+
+        $this->assertNull(await($original->callAsync('GET', $prefix . 'doesnotexist')));
+        $promise = $original->callAsync('GET', $prefix . 'doesnotexist');
+
+        $redis = clone $original;
+
+        $this->assertNull(await($redis->callAsync('GET', $prefix . 'doesnotexist')));
+        $this->assertNull(await($promise));
+    }
+
+    public function testCloneReturnsClientNotAffectedByPubSubSubscriptions(): void
+    {
+        $prefix = 'test:' . mt_rand() . ':';
+        $consumer = new RedisClient($this->uri);
+
+        $consumer->on('message', $this->expectCallableNever());
+        $consumer->on('pmessage', $this->expectCallableNever());
+        await($consumer->callAsync('SUBSCRIBE', $prefix . 'demo'));
+        await($consumer->callAsync('PSUBSCRIBE', $prefix . '*'));
+
+        $redis = clone $consumer;
+        $consumer->close();
+
+        $this->assertNull(await($redis->callAsync('GET', $prefix . 'doesnotexist')));
+    }
 }
diff --git a/tests/RedisClientTest.php b/tests/RedisClientTest.php
index 785bfbc..b17e148 100644
--- a/tests/RedisClientTest.php
+++ b/tests/RedisClientTest.php
@@ -836,4 +836,36 @@ public function testBlpopWillRejectWhenUnderlyingClientClosesWhileWaitingForResp
 
         $promise->then(null, $this->expectCallableOnceWith($e));
     }
+
+    public function testCloneClosedClientReturnsClientThatWillCreateNewConnectionForFirstCommand(): void
+    {
+        $this->redis->close();
+
+        $redis = clone $this->redis;
+
+        $deferred = new Deferred($this->expectCallableNever());
+        $this->factory->expects($this->once())->method('createClient')->willReturn($deferred->promise());
+
+        $promise = $redis->callAsync('PING');
+
+        $promise->then($this->expectCallableNever(), $this->expectCallableNever());
+    }
+
+    public function testCloneClientReturnsClientThatWillNotBeAffectedByOldClientClosing(): void
+    {
+        $this->redis->on('close', $this->expectCallableOnce());
+
+        $redis = clone $this->redis;
+
+        $this->assertEquals([], $redis->listeners());
+
+        $deferred = new Deferred($this->expectCallableNever());
+        $this->factory->expects($this->once())->method('createClient')->willReturn($deferred->promise());
+
+        $promise = $redis->callAsync('PING');
+
+        $this->redis->close();
+
+        $promise->then($this->expectCallableNever(), $this->expectCallableNever());
+    }
 }