Redis Error Guide: 'READONLY You can't write against a read only replica' — Point Writes at the Master
Fix READONLY You can't write against a read only replica in Redis: diagnose writing to a replica, stale topology after failover, Sentinel/Cluster routing, and replica-read-only.
- #redis
- #troubleshooting
- #errors
- #replication
Overview
READONLY You can't write against a read only replica means your client sent a write command (SET, DEL, INCR, EXPIRE) to a Redis node that is currently a replica. By default replica-read-only yes, so replicas reject writes to protect the master→replica data flow. The write must go to the master.
The literal error clients receive:
(error) READONLY You can't write against a read only replica.
This is almost always a topology problem, not a Redis bug: either the client is hard-wired to a node that is (or became) a replica, or a failover promoted a different node and the client’s view of “who is master” is stale. It commonly appears seconds after a Sentinel/Cluster failover, or when a read replica endpoint was mistakenly used for writes.
Symptoms
- Writes fail with
READONLYwhile reads succeed on the same connection. - Appeared right after a failover or a maintenance restart.
- Only some clients fail (those pinned to the old master), others are fine.
redis-cli -h 10.0.0.31 SET k v
(error) READONLY You can't write against a read only replica.
redis-cli -h 10.0.0.31 INFO replication | grep role
role:slave
Common Root Causes
1. Client is writing to a replica node
The connection string points at a replica endpoint, or a load balancer spread writes across all nodes including replicas.
redis-cli -h <HOST> INFO replication | grep -E 'role|master_host'
role:slave
master_host:10.0.0.30
role:slave on the write target is the direct cause.
2. Stale topology after a failover
Sentinel or Cluster promoted a new master, but the client cached the old address, which is now a replica.
redis-cli -h <SENTINEL_HOST> -p 26379 SENTINEL get-master-addr-by-name mymaster
1) "10.0.0.32"
2) "6379"
If the client still writes to 10.0.0.30 but Sentinel says the master is 10.0.0.32, the client view is stale.
3. A former master demoted itself
A master that lost quorum or was restarted came back as a replica of the new master.
redis-cli -h 10.0.0.30 INFO replication | grep -E 'role|master_link_status'
role:slave
master_link_status:up
4. Cluster: writing to a replica of the correct slot
In Cluster mode, the slot’s replica will reply READONLY (unless READONLY command was issued) — writes must go to the slot’s master.
redis-cli -c -h <HOST> CLUSTER NODES | grep -E 'master|slave'
Diagnostic Workflow
Step 1: Confirm the target node’s role
redis-cli -h <WRITE_TARGET> INFO replication | grep -E 'role|master_host|master_link_status'
role:slave means you are writing to a replica — that is the whole problem.
Step 2: Find the real master
# Sentinel deployments
redis-cli -h <SENTINEL_HOST> -p 26379 SENTINEL get-master-addr-by-name mymaster
redis-cli -h <SENTINEL_HOST> -p 26379 SENTINEL masters | grep -A2 name
# Cluster deployments
redis-cli -h <HOST> CLUSTER NODES | awk '/master/ {print $2, $3}'
Step 3: Verify replication health
redis-cli -h <MASTER> INFO replication | grep -E 'role|connected_slaves|slave0'
redis-cli -h <REPLICA> INFO replication | grep -E 'master_link_status|master_sync_in_progress'
Step 4: Check the failover history in the log
sudo journalctl -u redis-server --no-pager | grep -iE 'MASTER|REPLICAOF|failover|role' | tail
# Sentinel log
sudo journalctl -u redis-sentinel --no-pager | grep -iE 'switch-master|failover' | tail
+switch-master mymaster 10.0.0.30 6379 10.0.0.32 6379
Step 5: Confirm client configuration / discovery
grep -Eri 'REDIS_URL|sentinel|master_name|read' /etc/myapp/ 2>/dev/null
Example Root Cause Analysis
At 04:47 the order service starts throwing READONLY You can't write against a read only replica on every write. Reads still work. The timing lines up with a Sentinel alert, so a failover is the prime suspect.
The Sentinel log confirms a master switch:
+switch-master mymaster 10.0.0.30 6379 10.0.0.32 6379
The service, however, connects with a static REDIS_URL of redis://10.0.0.30:6379/0 — the old master, now a replica:
redis-cli -h 10.0.0.30 INFO replication | grep role # role:slave
redis-cli -h sentinel -p 26379 SENTINEL get-master-addr-by-name mymaster
# -> 10.0.0.32 6379
The root cause is a client that does not use Sentinel discovery and is pinned to a fixed IP. The immediate fix is to repoint at the new master; the real fix is Sentinel-aware connection:
# Immediate: point at current master
sudo sed -i 's#10.0.0.30#10.0.0.32#' /etc/myapp/redis.env
sudo systemctl restart order-service
# Real fix: use a Sentinel-aware client (pseudocode config)
# redis+sentinel://sentinel-a:26379,sentinel-b:26379/mymaster/0
After switching to Sentinel-based discovery the client automatically follows future failovers and READONLY no longer recurs.
Prevention Best Practices
- Use a Sentinel-aware or Cluster-aware client that discovers the current master instead of hard-coding a node IP.
- Route writes to the master and reads to replicas explicitly; never send writes to a read-replica endpoint or a round-robin LB that includes replicas.
- Keep
replica-read-only yes— it is the safety net; do not “fix” READONLY by flipping it tono, which invites split-brain data loss. - After a failover, confirm clients re-resolved the master; alert if a client keeps hitting a replica for writes.
- In Cluster mode let the client follow
MOVEDredirects (use cluster mode-c/ a cluster client) rather than pinning to nodes. - Test failover regularly (
SENTINEL failover mymaster) so client behavior is known before an incident. - Drop the failover log lines into the free incident assistant, and see more Redis guides.
Quick Command Reference
# What role is the write target?
redis-cli -h <TARGET> INFO replication | grep -E 'role|master_host|master_link_status'
# Who is the real master?
redis-cli -h <SENTINEL> -p 26379 SENTINEL get-master-addr-by-name mymaster
redis-cli -h <HOST> CLUSTER NODES | awk '/master/ {print $2,$3}'
# Replication health
redis-cli -h <MASTER> INFO replication | grep -E 'connected_slaves|slave0'
# Failover history
sudo journalctl -u redis-sentinel | grep -iE 'switch-master|failover' | tail
Conclusion
READONLY You can't write against a read only replica is a topology error: your write reached a replica, which refuses it because replica-read-only yes. The typical root causes are:
- The client is writing to a replica endpoint.
- Stale topology after a Sentinel/Cluster failover.
- A former master that came back as a replica.
- In Cluster mode, writing to a slot’s replica instead of its master.
Confirm the target’s role, discover the current master via Sentinel or CLUSTER NODES, and fix the client so it follows failovers automatically. The durable fix is a topology-aware client — not disabling replica-read-only.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.