InletDownload

Redis error READONLY

READONLY You can't write against a read only replica

The server you sent the write to is a replica, and replicas refuse writes by default. Connect to the primary instead: check the endpoint you use, and reconnect after a failover, because the old primary becomes a replica and keeps your connection open.

READONLY You can't write against a read only replica.

Tested on Redis 8.10.2 and Valkey 8.1.10 (temporary primary and replica servers) · Updated 9 October 2026

What it means

Redis replication copies one server, the primary, to one or more replicas. Since Redis 2.6 replicas are read-only by default (replica-read-only yes): they answer reads and refuse every command that could change data, with this error. Nothing was written.

So the question is why your client is talking to a replica. Either the address you use points at one, or the server you connected to was the primary and has since been turned into a replica, usually by a failover. Redis itself keeps existing connections open when its role changes: in the test below, one connection’s first SET returned OK and its second, after a FAILOVER, got READONLY.

Some commands that look like reads count as writes on a replica:

  • SORT (because of its STORE option): use SORT_RO.
  • EVAL scripts that write. A script without flags that only reads runs; one with a #!lua line needs flags=no-writes; or use EVAL_RO and EVALSHA_RO (and FCALL_RO for functions).

Common causes

  1. A replica’s address in your settings. A node address copied from a console, a Docker Compose service that’s the replica, or a load balancer that spreads connections over every node.
  2. A reader endpoint. On AWS ElastiCache (cluster mode disabled) the reader endpoint leads to a replica, and each node endpoint to one particular node, which may be a replica; writes belong on the primary endpoint.
  3. A failover. Sentinel, a managed service or an operator promoted a replica. Unless something closes them (Sentinel kills clients when it reconfigures a server), connections to the old primary stay open, so a connection pool keeps writing to a server that is now a replica until those connections are replaced. A client that caches DNS or uses the node’s IP address does the same after reconnecting.
  4. A server configured as a replica by mistake: a replicaof line left in redis.conf, or a REPLICAOF command run against the wrong server.
  5. Scripts or SORT sent to a replica on purpose, for reads, without their read-only variants.

How to fix it

Check what the server is

redis-cli -h <host> -p <port> ROLE
redis-cli -h <host> -p <port> INFO replication

ROLE starts with master or slave. On a replica, INFO replication shows role:slave and master_host/master_port, the primary it follows (as the replica sees it, which may be an internal address).

Connect to the primary

  • Your own servers: use the primary’s address. With Sentinel, ask it where the primary is (SENTINEL get-master-addr-by-name <name>) or use a client that does this for you.
  • ElastiCache (cluster mode disabled): use the primary endpoint for writes. AWS’s docs say it always resolves to the primary, including after a replica is promoted.
  • Read and write splitting: send writes to the primary and only reads to replicas or reader endpoints.

Recover cleanly after a failover

Make your application drop its connections and connect again when it sees READONLY: the new connections go to the current primary, as long as the client looks the address up again (a primary endpoint or Sentinel) rather than reusing an IP address. Restarting the application does the same.

Use the read-only variants on replicas

SORT_RO <key>
EVAL_RO "return redis.call('GET', KEYS[1])" 1 <key>

Or give a script #!lua flags=no-writes as its first line.

If this server should be a primary

If a server was made a replica by mistake, promote it:

redis-cli REPLICAOF NO ONE

Check first that no other primary is taking writes for the same data, and remove any replicaof line from redis.conf so it doesn’t come back after a restart.

Writable replicas

CONFIG SET replica-read-only no makes a replica accept writes, but Redis’s documentation advises against it: writes to a replica aren’t sent anywhere else, can clash with what the primary sends, and are lost when the replica resyncs or restarts.

Reproduce it

Two temporary Redis 8.10.2 containers on their own Docker network, the second a replica of the first:

docker network create seo-redis-net
docker run --rm -d --name seo-redis-primary --network seo-redis-net redis:8 redis-server
docker run --rm -d --name seo-redis-replica --network seo-redis-net redis:8 redis-server --replicaof seo-redis-primary 6379

After SET greeting hello on the primary, the replica returned "hello" for GET greeting, and SET, DEL and INCR each got:

(error) READONLY You can't write against a read only replica.
role:slave
master_host:seo-redis-primary
master_port:6379
master_link_status:up

On the replica, SORT seo:nums got the same error and SORT_RO seo:nums returned the sorted list. A script that only read returned (integer) 3; one that wrote got:

(error) READONLY You can't write against a read only replica. script: d2f84881259672f244702986adb7b49014b25995, on @user_script:1.

The same read-only script with a bare #!lua first line was refused too; with #!lua flags=no-writes, or sent with EVAL_RO, it ran.

Then a failover. One connection to the primary sent SET seo:a 1; meanwhile another connection ran FAILOVER (which hands the primary role to the replica); then the first connection sent SET seo:a 2 and ROLE:

OK
OK
(error) READONLY You can't write against a read only replica.
1) "slave"
2) "192.168.155.2"
3) (integer) 6379
4) "connected"

The connection stayed open throughout: only the server’s role changed under it.

CONFIG SET replica-read-only no on a replica made its writes succeed. A temporary Valkey 8.1.10 primary and replica gave the same message, word for word.

In Inlet

Inlet shows the server’s message and links it to this page. Run ROLE or INFO replication in a query tab (INFO shows as a table) to see which server you’re on, and connect to the primary for writes. This error is the server’s refusal; on a connection tagged production, Inlet also refuses writes itself, before they’re sent, whichever server you’re connected to.

Related

Sources