This error means your Redis client tried to execute a write command on a replica that’s configured to only accept reads, and the replica correctly refused.

The most common reason is that your application isn’t aware of which Redis instance is the master and which are replicas, and it’s sending write commands to the wrong place. This can happen if your connection pool or client library isn’t configured to route writes to the master.

Cause 1: Application logic sending writes to replicas.

  • Diagnosis: Connect to your replica instance using redis-cli -h <replica_host> -p <replica_port>. Then run INFO replication. Look for role:slave. If it’s role:slave, your client is talking to a replica. Try running a simple write command like SET testkey testvalue. You should get (error) READONLY You can't write against a read only replica..
  • Fix: Reconfigure your application’s Redis client or connection pool to ensure write commands (SET, DEL, HSET, LPUSH, etc.) are always directed to the master instance. If you’re using a sentinel setup, ensure your client is configured to use Redis Sentinel to discover the master.
  • Why it works: Redis replication is unidirectional. Replicas are passive mirrors of the master’s data; any writes must originate from the master and then be propagated.

Cause 2: Redis Sentinel misconfiguration or failure.

  • Diagnosis: If you’re using Redis Sentinel for high availability, check the Sentinel logs (/var/log/redis/sentinel.log or similar). Look for errors related to failing to connect to the master or quorum issues. Run redis-cli -p <sentinel_port> SENTINEL masters and redis-cli -p <sentinel_port> SENTINEL replicas <master_name> to see Sentinel’s view of your topology. Ensure the master is marked as s_down_time:0 and master-failover-state:ok.
  • Fix: Ensure your Sentinel instances have a quorum (e.g., sentinel quorum <master_name> 2) that allows them to agree on a master failure. Restart any Sentinel processes that are stuck or unresponsive. Verify that Sentinel can reach all Redis instances.
  • Why it works: Sentinel’s primary job is to monitor the master and orchestrate failovers. If it incorrectly believes the master is down or cannot reach it, it might not correctly inform clients where to send writes.

Cause 3: Replica’s replica-read-only configuration.

  • Diagnosis: Connect to your replica instance with redis-cli -h <replica_host> -p <replica_port>. Run CONFIG GET replica-read-only. If the output is 1, it’s enforcing read-only mode.
  • Fix: Edit your redis.conf file on the replica and set replica-read-only no. Then, restart the Redis server process for that replica.
  • Why it works: This directive explicitly controls whether a replica will accept write commands. Setting it to no allows writes, though this is generally discouraged for standard replication setups as it can lead to data divergence.

Cause 4: Master-replica replication lag.

  • Diagnosis: On your master, run redis-cli INFO replication. Note the master_repl_offset. On your replica, run redis-cli INFO replication. Note the slave_repl_offset. Calculate the difference: master_repl_offset - slave_repl_offset. A large, consistently growing difference indicates significant lag.
  • Fix: Ensure sufficient network bandwidth between your master and replicas. Check for network latency or packet loss. If the master is overloaded, optimize its performance (e.g., reduce RDB save frequency, tune maxmemory). If the replica is overloaded, scale its resources.
  • Why it works: While this doesn’t directly cause the READONLY error (the replica should refuse writes regardless of lag), severe lag can sometimes be a symptom of underlying network or resource issues that might also affect how quickly Sentinel detects master failures, indirectly impacting failover and client redirection. More importantly, if you did temporarily allow writes on a replica (Cause 3), this lag means data might be stale.

Cause 5: READONLY command manually executed on replica.

  • Diagnosis: Connect to the replica instance (redis-cli -h <replica_host> -p <replica_port>). Run LASTSAVE. If the save time is very old or LASTSAVE returns 0, the replica might have been started in a state where it hasn’t yet synced from the master, or it was manually reset. Check the replica’s redis.conf for any slaveof directives.
  • Fix: If the replica was intended to be a read-only replica, ensure it is properly configured to replicate from the master. If the slaveof directive is missing or incorrect in redis.conf, add/correct it and restart the replica. If the replica was manually put into read-only mode with the READONLY command, this state is not persistent across restarts. A restart of the replica will clear the READONLY state.
  • Why it works: The READONLY command is a client-side command that can be sent to any Redis instance to enforce read-only mode for the current connection. While it’s not typically used in production for enforcing read-only for all clients, if it was run, that specific connection will be blocked from writing. This state is connection-specific and lost on disconnect.

Cause 6: Connection pooling and stale connections.

  • Diagnosis: If your application uses a connection pool, a connection might have been established when the instance was the master, but then the instance was demoted (or a failover occurred) and it became a replica. The pool might still be returning this "stale" connection for writes. Check your connection pool’s configuration for settings related to connection validation or re-establishment after topology changes.
  • Fix: Configure your connection pool to validate connections before use or to automatically re-establish connections if they become invalid. Many client libraries have specific mechanisms for dynamic discovery of the master in a Sentinel setup.
  • Why it works: Connection pools aim for performance by reusing connections. If the pool doesn’t detect that the underlying instance’s role has changed, it will continue to send write commands to an instance that is no longer the master.

The next error you’ll likely encounter, after ensuring writes go to the master, is a MOVED error if your client isn’t correctly handling cluster redirections or if you’re not using Sentinel and have a stale master IP.

Want structured learning?

Take the full Redis course →