You need to patch the host under a standalone Valkey primary, so you promote a replica first, and the application still logs errors. Writes that reach the old primary after the role swap return READONLY You can't write against a read only replica. A BLPOP waiting on it returns UNBLOCKED and loses its connection. Valkey has two features that remove most of these errors. The FAILOVER command pauses writes, waits for the replica to catch up, and swaps roles. CLIENT CAPA redirect, added in Valkey 8.0, makes the demoted node answer -REDIRECT host:port, so the client can follow the new primary itself. This post covers how the two work together, which client libraries support the capability as of November 2026, what changed in Valkey 9.0 and the 9.2 release candidates, and a maintenance runbook.
FAILOVER TO <host> <port> TIMEOUT <ms>pauses writes, waits until the target replica has the primary's full replication offset, then swaps roles. Cluster mode rejects it.- A connection that sent
CLIENT CAPA redirect(Valkey 8.0 and later) gets-REDIRECT <new-primary>:<port>from the demoted node instead of-READONLY, for reads as well as writes. - Client support is thin. valkey-go, valkey-java, Redisson, and valkey-swift send the capability. GLIDE, redis-py, Jedis, go-redis, Lettuce, node-redis, and ioredis do not, as of November 2026.
- Valkey 9.0 redirects blocked commands such as
BLPOPinstead of failing them with-UNBLOCKED. The 9.2 release candidates extend REDIRECT to keyless commands on cluster replicas, which the project labels a breaking change. FAILOVERdoes not rewritevalkey.conf. Persist the new roles before you restart the old primary, and on a Sentinel-managed primary useSENTINEL FAILOVER <name> COORDINATED(Valkey 9.0 and later) instead.
Scope and review date: November 2026. This post covers self-managed Valkey 8.0 to 9.1.3 in standalone mode: one primary with replicas, with or without Sentinel. Behaviour from the 9.2 release candidates (newest: 9.2.0-rc2, 4 November 2026) is labelled as such. Commands, error strings, and client library behaviour were checked against the Valkey documentation, the Valkey 9.1.3 source, and each client library's repository on 10 November 2026. They were not run in a lab, so rehearse the runbook on staging.
What do clients see when a Valkey primary becomes a replica?
In standalone mode, a primary that turns into a replica keeps its client connections open, and nothing tells those clients that the role changed. With the default replica-read-only yes, three things follow for a client that has not declared any capability:
- Writes fail with
-READONLY You can't write against a read only replica. - Reads succeed, served by the demoted node, which now replicates from the new primary.
- Commands blocked on lists, sorted sets, or streams are released with
-UNBLOCKED, and the server closes the connection after the reply.
# Which role does each node hold right now?
valkey-cli -h 10.0.0.11 -p 6379 ROLE
valkey-cli -h 10.0.0.12 -p 6379 ROLEInterpretation: the first element of the reply is master or slave. Applications do not check the role before every command, so the error reply is usually their first sign. Without a redirect, they reach the new primary only after a DNS record, virtual IP, proxy, or Sentinel lookup changes.
The old primary's replies after a switchover
Switch tabs to compare a connection without the redirect capability and one that sent CLIENT CAPA redirect
Without CAPA redirect
| What the client sends to 10.0.0.11 | Reply |
|---|---|
| A write while FAILOVER waits for the replica | Held by the write pause |
| A read during the role swap | Served locally by the demoting node |
| A write after the swap | -READONLY You can't write against a read only replica. |
| A read after the swap | Served locally; the node is now a replica |
A BLPOP waiting at the swap | -UNBLOCKED, then the connection is closed |
A write inside EVAL after the swap | -READONLY |
| How the client finds the new primary | DNS, virtual IP, config change, or Sentinel |
With CAPA redirect
| What the client sends to 10.0.0.11 | Reply |
|---|---|
| A write while FAILOVER waits for the replica | Held by the write pause |
| A read during the role swap | Held until the new primary is promoted, then redirected |
| A write after the swap | -REDIRECT 10.0.0.12:6379 |
| A read after the swap | -REDIRECT 10.0.0.12:6379, unless the connection sent READONLY |
A BLPOP waiting at the swap | -REDIRECT 10.0.0.12:6379 on 9.0 and later; -UNBLOCKED on 8.x |
A write inside EVAL after the swap | -READONLY (issue #868 is still open) |
| How the client finds the new primary | The address in the -REDIRECT reply |
Errors become directions: a redirect-capable client still receives an error reply, but the reply carries the new primary's address, so the library can retry there without waiting for an endpoint change.
With replica-read-only no, clients without the redirect capability can keep writing to the demoted node, and those writes are never replicated. Check that every node has the default, yes.
How does the FAILOVER command switch a standalone primary?
FAILOVER dates from Redis 6.2.0 and is the standalone counterpart of CLUSTER FAILOVER. Per the FAILOVER command reference, the primary starts an internal CLIENT PAUSE WRITE, waits for a replica to acknowledge its whole replication offset, and demotes itself. It then sends PSYNC FAILOVER to the target, which promotes itself, and unpauses its clients. If the target refuses, the primary aborts and returns to normal; it keeps its data throughout.
A planned FAILOVER from 10.0.0.11 to 10.0.0.12
Follow the numbers: writes pause in step 1, roles swap in step 2, and redirect-capable clients move in step 3
Bound the pause: without TIMEOUT, step 2 has no upper limit and writes stay paused until the replica catches up or you run FAILOVER ABORT.
The command takes three options. TO host port names the replica to wait for; without it, the primary fails over to the first replica that catches up. TIMEOUT milliseconds caps the time in waiting-for-sync and so caps the write outage. FORCE, which needs both TO and TIMEOUT, fails over to the target when the timeout expires instead of rolling back.
# Planned switchover to a named replica, with writes paused for at most 5 s
valkey-cli -h 10.0.0.11 -p 6379 FAILOVER TO 10.0.0.12 6379 TIMEOUT 5000
# Cancel it while the state is still waiting-for-sync
valkey-cli -h 10.0.0.11 -p 6379 FAILOVER ABORTInterpretation: OK means the failover has started, not that it finished. A background task does the work, so you watch the state separately. The host and port must match the replica as the primary lists it in INFO replication: its replica-announce-ip or connection address, and its listening port.
The 9.1.3 source rejects a FAILOVER up front in these cases:
| Error reply | Cause |
|---|---|
FAILOVER target HOST and PORT is not a replica. | The address matches no replica line in INFO replication |
FAILOVER target replica is not online. | The target is syncing or disconnected |
FAILOVER is not valid when server is a replica. | You ran it on a replica |
FAILOVER not allowed in cluster mode. Use CLUSTER FAILOVER command instead. | The node runs with cluster-enabled yes |
# Poll the failover state on the old primary
valkey-cli -h 10.0.0.11 -p 6379 INFO replication | grep -E '^(role|master_host|master_failover_state)'Interpretation: master_failover_state moves from no-failover to waiting-for-sync to failover-in-progress, then back. Success means role:slave with master_host set to the target. A role:master line means it aborted, and the server log says why.
With FORCE, the primary hands over at the timeout even if the replica lags, so writes the replica never received are lost when the old primary resyncs. Use it only when a bounded outage matters more than those writes.
What does CLIENT PAUSE WRITE do to application traffic?
During waiting-for-sync, the primary holds writes; it does not reject them. The CLIENT PAUSE reference lists what else the WRITE mode holds: every EVAL and EVALSHA script, PUBLISH, PFCOUNT, and the acknowledgements for WAIT and WAITAOF. Plain reads keep running. Keys also stop expiring and being evicted during the pause, so the dataset is static while the replica catches up.
A held command occupies its connection, so pipelines and pools can stall behind it, and a client whose command timeout is shorter than the pause sees a timeout instead of a reply. The documentation says failovers typically take under a second, but longer under heavy writes or with a lagging replica. Set TIMEOUT below the shortest command timeout your clients use.
# Valkey 8.1 and later: is the node paused, and why?
valkey-cli -h 10.0.0.11 -p 6379 INFO clients | grep -E '^paused_'Interpretation: during a FAILOVER, expect paused_reason:failover_in_progress and paused_actions:write. paused_reason:client_pause means a manual or Sentinel-issued CLIENT PAUSE is in force. These fields arrived in Valkey 8.1.0. The CLIENT PAUSE page still describes the older manual procedure (pause, wait a few seconds, promote); FAILOVER checks the replication offset instead of waiting a fixed time.
What does CLIENT CAPA redirect change for clients?
CLIENT CAPA arrived in Valkey 8.0.0 (GA on 15 September 2024, from PR #325). A client declares capabilities for its own connection, and the server ignores any it does not recognise; redirect is the only one today. On a standalone replica, a redirect-capable connection gets -REDIRECT primary-ip:port for every read and write command, and must send READONLY before it can read there. The address can be IPv6, so clients split host and port at the last colon. On a primary, the capability changes nothing until that primary is demoted.
# On the old primary after the switchover: find redirect-capable connections
valkey-cli -h 10.0.0.11 -p 6379 CLIENT LIST TYPE normal CAPA r
# Valkey 8.1: no CAPA filter yet, so search the capa field instead
valkey-cli -h 10.0.0.11 -p 6379 CLIENT LIST TYPE normal | grep -c 'capa=r'Interpretation: CLIENT LIST shows a capa= field from Valkey 8.1, where r means redirect. The CAPA and NOT-CAPA filters arrived in 9.0. On 8.0 there is no way to list the capability, so check the client configuration instead.
One connection to the old primary, before and after CLIENT CAPA redirect
Illustrative output: the first SET waits out the write pause, then fails once the node is a replica
Same node, better answer: after CLIENT CAPA redirect, the demoted node names the new primary instead of refusing the write. Both error strings match the Valkey 9.1.3 source; valkey-cli prints REDIRECT but does not follow it.
In failover-in-progress, both nodes can be replicas for a moment, so a REDIRECT could bounce between them. Since 8.0.0-rc2 (PR #871), the old primary suspends redirect-capable clients during that phase and releases them once the target is promoted. Inside MULTI, a redirected command makes EXEC fail, so the client must replay the whole transaction on the new primary.
PR #325 called this "a breaking change": a connection with the capability that reads from a replica on purpose now gets REDIRECT. Send READONLY on those connections, or leave the capability off.
Which Valkey client libraries support CLIENT CAPA redirect?
Fewer than you might expect. The Valkey clients page badges four libraries with "Advanced capabilities" but describes the badge as handing off "slot redirections", which are MOVED and ASK. So we checked each library's source for the CLIENT CAPA redirect call and for -REDIRECT handling.
| Library (latest release checked) | Sends CLIENT CAPA redirect | On a -REDIRECT reply |
|---|---|---|
| valkey-go 1.0.79 | Opt-in: StandaloneOption.EnableRedirect | Swaps its primary connection to the new address and retries; cannot be combined with ReplicaAddress |
| valkey-java 5.5.0 | On by default (ClientCapaConfig.DEFAULT); off with ClientCapaConfig.DISABLED | Retries when UnifiedJedis is built with a RedirectConnectionProvider; otherwise raises JedisRedirectionException |
| Redisson 4.8.0 (setting added in 3.47.0) | Opt-in: valkeyCapabilities: REDIRECT | Retries the command at the address in the reply |
| valkey-swift 1.6.0 | On by default: enableClientCapaRedirect | Retries at the address in the reply |
| valkey-py 6.2.0 | Not in 6.2.0; client_capa_redirect=True is on the main branch since March 2026 | Raises RedirectError with the host and port; the application reconnects |
| Valkey GLIDE 2.5.3 | No; issue #2368, open since September 2024 | Not handled |
| redis-py, Jedis, go-redis, Lettuce, node-redis, ioredis, iovalkey | No | Not handled |
// valkey-go: standalone client that follows REDIRECT after a switchover
client, err := valkey.NewClient(valkey.ClientOption{
InitAddress: []string{"10.0.0.11:6379"},
Standalone: valkey.StandaloneOption{EnableRedirect: true},
})Interpretation: the client sends CLIENT CAPA redirect at connection setup. On a REDIRECT, it connects to the new primary and retries there. A new process still starts from InitAddress, so update that address after the switchover. The table reflects each library's default branch on 9 and 10 November 2026, checked against the named release; check the version you pin.
What happens to BLPOP and other blocked commands during a switchover?
Through Valkey 8.1, every client blocked on the primary was released with -UNBLOCKED force unblock from blocking operation, instance state changed (master -> replica?) when the node became a replica, and the server closed its connection. Valkey 9.0 changed this with PR #2329, shipped in 9.0.0-rc3 and GA on 21 October 2025.
- A redirect-capable client blocked on a list, sorted set, stream, or module key gets
-REDIRECT host:portand keeps its connection. - A client in
READONLYmode that is blocked by a read command stays blocked through the switchover. - Every other blocked client still gets
-UNBLOCKEDand is disconnected. - In cluster mode, the equivalent case now returns
-MOVED.
# A worker blocked on the old primary when FAILOVER completes
10.0.0.11:6379> CLIENT CAPA redirect
OK
10.0.0.11:6379> BLPOP jobs:email 0
(error) REDIRECT 10.0.0.12:6379Interpretation: the BLPOP had not popped anything, so resending it to the new primary is safe. The PR is labelled client-changes-needed: the library must treat this REDIRECT as retryable. On 8.x, expect a dropped connection, and let the worker reconnect with backoff.
Where does REDIRECT still fall short?
Scripts are the main gap. Issue #868, still open, shows that a write inside EVAL on a replica returns READONLY even after CLIENT CAPA redirect. Its reproduction, quoted from the issue:
localhost:6380> client capa redirect
OK
localhost:6380> set foo bar
(error) REDIRECT redis:6379
localhost:6380> EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 foo bar
(error) READONLY You can't write against a read only replica. script: d8f2fad9f8e86a53d2a6ebd960b33c4972cacc37, on @user_script:1.Interpretation: a library that follows REDIRECT still needs a READONLY handler for scripts and functions. PR #1781 would fix scripts, WATCH, and keyless transactions, but it is still open as of November 2026.
The 9.2 release candidates change cluster mode. PR #3505 (in 9.2.0-rc1) makes cluster replicas redirect keyless commands such as SCAN, DBSIZE, and FLUSHDB for redirect-capable clients that have not sent READONLY, and is labelled breaking-change. Standalone mode decides on REDIRECT from command flags, not keys, so in our reading of the source it already redirected these. The valkey.io pages for CLIENT CAPA and READONLY already describe the 9.2 behaviour with no version switcher, so ignore the "Since Valkey 9.2" lines on 9.1.3.
How do you run a maintenance switchover step by step?
This runbook moves the primary from 10.0.0.11 to 10.0.0.12 so 10.0.0.11 can be patched, with a third node, 10.0.0.13, as a second replica. It assumes no Sentinel; the next section covers Sentinel.
Maintenance switchover runbook: standalone Valkey
Eight steps; steps 3 and 4 are the write-pause window
-
List clients without the redirect capability
These connections will get READONLY and need an endpoint change. On 8.1, search CLIENT LIST output for capa=r.
valkey-cli -h 10.0.0.11 CLIENT LIST \ TYPE normal NOT-CAPA r -
Check the target replica
It must show state=online with lag near 0. Copy its ip and port exactly, and pick a TIMEOUT below your shortest client command timeout.
valkey-cli -h 10.0.0.11 INFO replication -
Start the switchover
Writes pausedThe reply OK only means it started. Scripts, PUBLISH, and WAIT are held too.
valkey-cli -h 10.0.0.11 \ FAILOVER TO 10.0.0.12 6379 TIMEOUT 5000 -
Watch the state until it settles
Writes pausedDone when role is slave, master_host is 10.0.0.12, and the state is no-failover. A master role means it aborted.
valkey-cli -h 10.0.0.11 INFO replication \ | grep -E '^(role|master_host|master_failover)' -
Confirm the new primary
The first element must be master. Check that application writes are arriving there.
valkey-cli -h 10.0.0.12 ROLE -
Re-point the other replicas
FAILOVER leaves 10.0.0.13 replicating through 10.0.0.11 as a chained replica.
valkey-cli -h 10.0.0.13 REPLICAOF 10.0.0.12 6379 -
Persist the new roles
FAILOVER does not edit valkey.conf. Without this, 10.0.0.11 restarts as a second primary.
for h in 10.0.0.11 10.0.0.12 10.0.0.13; do valkey-cli -h $h CONFIG REWRITE done -
Move the endpoint, then do the maintenance
Update DNS, the virtual IP, or client config to 10.0.0.12 for the clients from step 1 and for new processes. Then patch 10.0.0.11.
Rollback point: FAILOVER ABORT has no side effects only while the state is waiting-for-sync. After the swap, roll back by running FAILOVER TO 10.0.0.11 6379 TIMEOUT 5000 on 10.0.0.12.
The server log records each transition. These lines are taken from the log calls in the 9.1.3 source:
grep -E 'FAILOVER|Failover target|PRIMARY MODE' /var/log/valkey/valkey-server.log
# FAILOVER requested to 10.0.0.12:6379.
# Failover target 10.0.0.12:6379 is synced, failing over.
# FAILOVER to 10.0.0.12:6379 aborted: Replica never caught up before timeoutInterpretation: the first two lines appear on the old primary in a normal run, and the new primary logs PRIMARY MODE enabled when it accepts PSYNC FAILOVER. The third line means the replica missed the TIMEOUT and the old primary is still primary; find the lag before you retry. If configuration management owns valkey.conf, change it there instead of running CONFIG REWRITE, before the old primary restarts.
What changes when Sentinel manages the primary?
Do not run FAILOVER behind Sentinel's back. Sentinel still names the old primary, and in the 9.1.3 sentinel.c a primary that reports the replica role counts as unreachable, "so eventually a failover will be triggered", to a replica Sentinel picks.
From Valkey 9.0, Sentinel can do the planned version itself. The Sentinel documentation describes SENTINEL FAILOVER <primary name> COORDINATED: Sentinel wins a leader election and then "supervises an orderly handover using the FAILOVER command". It sends CLIENT PAUSE <ms> WRITE and FAILOVER TO ... TIMEOUT <ms> in one transaction, so the same write pause and offset check apply.
# Valkey 9.0 and later Sentinel: planned switchover for "mymaster"
valkey-cli -p 26379 SENTINEL FAILOVER mymaster COORDINATED
# Then confirm what Sentinel now reports as primary
valkey-cli -p 26379 SENTINEL GET-PRIMARY-ADDR-BY-NAME mymasterInterpretation: the second command should return the promoted replica's address. Without COORDINATED, SENTINEL FAILOVER forces a failover "as if the primary was not reachable". Older Sentinels have only that mode.
Clients behave differently here. In our reading of sentinel.c, after the coordinated promotion Sentinel runs CLIENT KILL TYPE normal and CLIENT KILL TYPE pubsub on both nodes, then CLIENT UNPAUSE. So Sentinel clients mostly act on a dropped connection, not a REDIRECT, and must ask a Sentinel for the primary again. The Sentinel user also needs extra ACL permissions; Sentinel on Valkey 9: coordinated failover and the ACL change covers them.
Frequently asked questions
Does the Valkey FAILOVER command work in cluster mode?
No. On a node with cluster-enabled yes, FAILOVER returns "FAILOVER not allowed in cluster mode. Use CLUSTER FAILOVER command instead." In a cluster, run CLUSTER FAILOVER on the replica you want to promote. Since Valkey 9.0, SHUTDOWN FAILOVER can also hand off a cluster primary before it stops.
Which Valkey version added CLIENT CAPA redirect?
Valkey 8.0.0, released on 15 September 2024. CLIENT LIST shows the capa field from 8.1, and the CAPA filters and redirects for blocked commands arrived in 9.0. The 9.2 release candidates extend REDIRECT to keyless commands on cluster replicas, which is not GA behaviour as of November 2026.
Does Valkey GLIDE support CLIENT CAPA redirect?
Not as of November 2026. GLIDE 2.5.3 neither sends CLIENT CAPA redirect nor handles the REDIRECT reply, and issue #2368 has been open since September 2024. valkey-go, valkey-java, Redisson, and valkey-swift support it; valkey-py has it on its main branch only.
Can a Valkey FAILOVER lose writes?
Without FORCE, no: the primary holds writes, hands over only after the target replica has its full replication offset, and rolls back on timeout. With FORCE, it hands over at the timeout even if the replica lags, so unreplicated writes are lost. FAILOVER ABORT during failover-in-progress can also leave two primaries.
Why do I still get READONLY errors after a planned Valkey failover?
Your client still writes to the demoted node without having sent CLIENT CAPA redirect, so the replica refuses the writes. Writes inside EVAL scripts return READONLY even with the capability (open issue #868). Update the client's endpoint, or use a library that sends the capability and follows the REDIRECT reply.
Key takeaways
- Use
FAILOVER TO host port TIMEOUT msfor planned standalone switchovers, with a timeout below your client command timeouts. CLIENT CAPA redirectturns READONLY errors into REDIRECT replies that carry the new primary's address, but only valkey-go, valkey-java, Redisson, and valkey-swift use it today.- Run Valkey 9.0 or later if you have blocking consumers; 8.x releases them with UNBLOCKED and drops their connections.
- After the swap, re-point chained replicas, persist roles with
CONFIG REWRITE, and move the endpoint before you restart the old primary. - Behind Sentinel, use
SENTINEL FAILOVER <name> COORDINATEDon 9.0 or later, and expect clients to be disconnected rather than redirected.
Plan Valkey switchovers with JusDB
JusDB's Valkey high availability team can review your primary and replica topology, Sentinel configuration, and client library settings. We can also write and rehearse a switchover runbook with your engineers.
Bring your Valkey versions, the client libraries and versions each service uses, and your current failover procedure. Your team approves every production change.