TL;DR
You sent a write command (SET, DEL, INCR, etc.) to a Redis replica node. Replicas are read-only by default โ they don't accept writes. Connect to the master node instead. Or, if you have a specific reason, temporarily allow writes on the replica with CONFIG SET replica-read-only no.
Why This Error Happens
Redis replication flows one way: master โ replica(s). The replica continuously syncs data from the master and rejects every write command with:
(error) DENY COMMANDS ASKING WRITE. REPLICA can't execute write commands.
A few situations that trip people up:
- You hardcoded a replica's IP/port in your app config and forgot to update it after a failover.
- Redis Sentinel promoted a new master, but your client is still pointing at the old one โ now a replica.
- You connected to the wrong port. In a typical two-node setup,
6379is the master and6380is the replica, but this varies. - Your connection pool round-robins across nodes without knowing which one is the master.
Check Which Node You're On
Run ROLE via redis-cli to see the node's role immediately:
redis-cli -h <host> -p <port> ROLE
A replica responds like this:
1) "slave"
2) "192.168.1.10"
3) (integer) 6379
4) "connected"
5) (integer) 12345
A master responds like this:
1) "master"
2) (integer) 12345
3) 1) 1) "192.168.1.11"
2) "6379"
3) "12345"
See slave in the output? You're on the wrong node for writes.
Fix 1: Connect to the Master Node (Recommended)
Run ROLE on each node to find the master, or use INFO replication:
redis-cli -h <host> -p <port> INFO replication
Find the line role:master. That host and port is where all writes should go.
Redis Sentinel Setup
Skip hardcoded IPs entirely. Ask Sentinel which node is currently the master:
redis-cli -h <sentinel-host> -p 26379 SENTINEL get-master-addr-by-name mymaster
This returns the current master's IP and port โ even after a failover. Better yet, use a Sentinel-aware client so your app never needs to ask manually:
# Python (redis-py)
from redis.sentinel import Sentinel
sentinel = Sentinel(
[('sentinel-host', 26379)],
socket_timeout=0.1
)
master = sentinel.master_for('mymaster', socket_timeout=0.1)
master.set('key', 'value') # Always routes to the current master
Redis Cluster Setup
Cluster-aware clients handle slot-to-master routing automatically. No manual node selection needed:
# Python (redis-py cluster)
from redis.cluster import RedisCluster
rc = RedisCluster(host='node1', port=6379, decode_responses=True)
rc.set('key', 'value') # Client figures out which shard master owns this key
Fix 2: Allow Writes on a Replica (Testing Only)
Sometimes you genuinely need to write to a replica โ say, during local testing or a one-off migration step. Disable read-only mode at runtime:
redis-cli -h <replica-host> -p <port> CONFIG SET replica-read-only no
On Redis older than 5.0, the config key was named differently:
redis-cli -h <replica-host> -p <port> CONFIG SET slave-read-only no
Warning: Anything you write directly to a replica gets wiped the next time the master syncs. This causes data divergence. Never use this in production without a solid plan.
To make the change survive a restart, edit redis.conf on the replica:
replica-read-only no
Then restart Redis:
sudo systemctl restart redis
Fix 3: After a Failover โ Update Your App Config
Sentinel or Cluster triggered a failover. Your app is still hardcoded to the old master's address โ which is now a replica. Update the config:
# Before failover (stale โ now pointing at a replica)
REDIS_HOST=192.168.1.10
REDIS_PORT=6379
# After failover (correct โ the new master)
REDIS_HOST=192.168.1.11
REDIS_PORT=6379
That fixes it short-term. For the long run, switch to a Sentinel or Cluster client. Your app will handle future failovers on its own, no config edits required.
Verify the Fix
Pointed at the master? Run a quick write/read/delete cycle to confirm:
redis-cli -h <master-host> -p 6379 SET testkey "hello"
# Expected: OK
redis-cli -h <master-host> -p 6379 GET testkey
# Expected: "hello"
redis-cli -h <master-host> -p 6379 DEL testkey
# Expected: (integer) 1
Also check that replication itself is healthy:
redis-cli -h <master-host> -p 6379 INFO replication | grep -E 'role|connected_slaves|slave'
You want to see role:master and at least one connected slave in the output.
Quick Reference: Which Setup Are You Using?
- Standalone replica: Run
ROLEon each node to find the master, then connect directly to it. - Redis Sentinel: Use
SENTINEL get-master-addr-by-name, or better โ a Sentinel-aware client library. - Redis Cluster: Use a cluster-aware client. It routes writes to the correct shard master automatically.

