JusDB
Free DB Audit
NoSQL Databases

Multi-AZ Valkey: Replica Placement, Failover Priority and Zone-Aware Clients

Lay out self-managed Valkey Cluster and Sentinel across availability zones so a zone loss keeps a voting majority, a replica for every shard and a predictable failover.

JusDB Team
Published November 7, 2026
Updated November 10, 2026
19 min read

You spread nine Valkey nodes across three availability zones, set availability-zone on each one, and expect a zone outage to cost you one failover. Then us-east-1a goes dark and every surviving node logs Cluster state changed: fail, because valkey-cli --cluster create made the first three nodes you listed, all in that zone, the primaries. In every GA release up to 9.1.3, availability-zone is a label the server reports to clients. Nothing on the server reads it when it places replicas, counts failover votes, or picks the replica to promote. This guide covers what 8.0, 8.1, 9.1 and the 9.2 release candidate added, how to place nodes yourself, how Sentinel and Cluster rank replicas, what must survive a zone loss, and checklists for 3-AZ and 2-AZ layouts.

TL;DR
  • availability-zone is free text: a config and INFO field in 8.0, a HELLO field in 8.1, and a CLUSTER SHARDS and CLUSTER SLOTS field in 9.1. No GA release uses it for placement or failover.
  • valkey-cli --cluster create spreads nodes by IP address only. Create one primary per zone with --cluster-replicas 0, then add each replica with --cluster-replica --cluster-primary-id.
  • A cluster survives a zone loss only if the other zones hold a majority of the slot-owning primaries and a replica of every lost primary. Keep fewer than half of the primaries in any one zone.
  • Sentinel ranks replica-priority above replication offset. Cluster ranks offset first, and the 9.2 release candidate's cluster-replica-priority only breaks ties.
  • A failover leaves two primaries in one zone. Move one back with CLUSTER FAILOVER when the lost zone returns.

Scope and review date: November 2026. This post covers self-managed Valkey Cluster and Sentinel on 8.0 to 9.1 (latest patches 9.1.3 and 9.0.7), with the 9.2 release candidate (9.2.0-rc2, 4 November 2026) marked where it differs. Managed services that set zones for you are out of scope. Commands and behaviour were checked on 10 November 2026 against the valkey.io documentation, the release notes and the 9.1.3 and 9.2.0-rc2 source. They were not run in a lab, so rehearse them on staging.


Which Valkey versions understand availability zones?

Zone support arrived in three pieces, and the cluster tutorial mentions none of them. PR #700, shipped in 8.0, added the availability-zone config (empty by default, changeable with CONFIG SET) and an availability_zone line in INFO server. Its description says using it "when performing failover" would be ideal in the future. 8.1 added the field to the HELLO reply when it is set. 9.1.0 gossips the zone between cluster nodes and adds it to every node in CLUSTER SHARDS and CLUSTER SLOTS (PR #3156), again only when set.

VersionWhat it addedWhere you see the zone
8.0availability-zone config, default emptyINFO server
8.1Zone in the HELLO reply when setHELLO 3
9.1Zone gossiped and kept in nodes.confCLUSTER SHARDS, CLUSTER SLOTS
9.2 release candidatecluster-replica-priority tie-breakervalkey.conf, election log
Sentinel, any versionNothing: Sentinel never reads the zoneNot applicable
ini
# valkey.conf on every node in us-east-1a
availability-zone "us-east-1a"
bash
# Or at runtime, then persist it
valkey-cli -h 10.0.1.11 CONFIG SET availability-zone us-east-1a
valkey-cli -h 10.0.1.11 CONFIG REWRITE
valkey-cli -h 10.0.1.11 INFO server | grep availability_zone

Interpretation: availability_zone:us-east-1a means the node reports its zone, and nothing after the colon means it is unset. In the 9.1.3 source a node reads its own zone from the config at startup, so a CONFIG SET never written to valkey.conf is lost on restart.

A label, not a decision

In the 9.1.3 source the zone appears only in replies, gossip and nodes.conf. Replica placement, replica migration, failure detection and elections never read it. It is free text, so spell it the same way on servers and clients.

What has to survive a zone loss in Valkey Cluster?

The cluster specification states it: the cluster survives partitions "where the majority of the primary nodes are reachable and there is at least one reachable replica for every primary node that is no longer reachable". Only primaries that own at least one slot count. A replica needs votes from (cluster_size / 2) + 1 of them, and a node that can reach fewer marks the cluster failed. With cluster-require-full-coverage yes (the default), one shard without an owner stops the whole cluster.

bash
valkey-cli -h 10.0.2.11 CLUSTER INFO | grep -E 'cluster_state|cluster_size'

Interpretation: cluster_size is the number of slot-owning primaries. With cluster_size:3 a failover needs 2 votes, so no zone may hold more than one primary.

The general rule: the primaries in any one zone must be fewer than half of cluster_size.

Slot-owning primariesVotes neededMost in one zoneFits in three zones?
321Yes: 1, 1, 1
431No: one zone must hold 2
532Yes: 2, 2, 1
642Yes: 2, 2, 2

Four shards in three zones is the trap: losing the zone with two primaries leaves two votes where three are needed.

Three shards in three zones, and zone A goes dark

Pn is the primary of shard n and Rn a replica of it; each zone holds one primary and two replicas

Zone loss in a three-zone Valkey cluster Three zones each hold one primary and two replicas of other shards: zone A holds P1, R2 and R3, zone B holds P2, R1 and R3, and zone C holds P3, R1 and R2. Step 1: zone A is lost, taking P1 with it. Step 2: P2 in zone B and P3 in zone C are two of three slot-owning primaries, a majority, so they vote. Step 3: the replica of shard 1 in zone B is promoted. When zone A returns, the old P1 rejoins as a replica of the new primary. Zone A P1 + R2 + R3 Zone B P2 + R1 + R3 Zone C P3 + R1 + R2 Shard 1 R1 in zone B promoted 1 zone A lost 2 2 of 3 primaries vote 3 zone A returns: P1 rejoins as a replica Pn primary of shard n, Rn replica

After step 3: zone B holds two of the three primaries. Until one moves back to zone A, losing zone B leaves one vote where two are needed.

Why does valkey-cli --cluster create ignore zones?

It only knows IP addresses. In the 9.1.3 valkey-cli.c, create groups nodes by IP, interleaves the groups, and takes the first N nodes as primaries. Its anti-affinity score only penalizes replicas sharing an IP with their primary or a sibling. When every node has its own IP, the order you type decides the layout.

bash
# Listed zone by zone: the first three addresses become the primaries
valkey-cli --cluster create \
  10.0.1.11:6379 10.0.1.12:6379 10.0.1.13:6379 \
  10.0.2.11:6379 10.0.2.12:6379 10.0.2.13:6379 \
  10.0.3.11:6379 10.0.3.12:6379 10.0.3.13:6379 \
  --cluster-replicas 2

Interpretation: by our reading of the source, this makes all three 10.0.1.x nodes primaries, and the score is already zero, so nothing gets moved. Listing zones in turn (a, b, c, a, b, c) spreads the primaries but can still put a replica in its primary's zone. Read every Adding replica line before you answer Can I set the above configuration?.

The predictable layout is primaries first, then each replica placed by hand:

bash
# 1. One primary per zone, no replicas yet
valkey-cli --cluster create \
  10.0.1.11:6379 10.0.2.11:6379 10.0.3.11:6379 \
  --cluster-replicas 0
bash
# 2. Replicas of the zone A primary go to zones B and C
PA=$(valkey-cli -h 10.0.1.11 -p 6379 CLUSTER MYID)
valkey-cli --cluster add-node 10.0.2.12:6379 10.0.1.11:6379 \
  --cluster-replica --cluster-primary-id "$PA"
valkey-cli --cluster add-node 10.0.3.12:6379 10.0.1.11:6379 \
  --cluster-replica --cluster-primary-id "$PA"

Interpretation: --cluster-primary-id works from 8.0, beside the older --cluster-master-id. Repeat for the zone B primary (replicas in C and A) and the zone C primary (replicas in A and B).

Replica migration is zone-blind too: with the defaults cluster-allow-replica-migration yes and cluster-migration-barrier 1, a spare replica can move to an orphaned primary in its own zone. Re-check placement after any node replacement, and see replacing a failed Valkey Cluster node for the safe order.

Placing primaries and replicas across three zones

Seven steps for a new 3-shard cluster with two replicas per shard; none of them is an outage

  1. Set the zone in every node's valkey.conf

    Use the spelling your clients will use, in the file rather than only in CONFIG SET.

    cluster-enabled yes availability-zone "us-east-1a"
  2. Start the nodes and check each zone

    An empty value after the colon means the line did not load.

    valkey-cli -h 10.0.1.11 INFO server \ | grep availability_zone
  3. Create one primary per zone

    Three addresses in three zones and no replicas, so the order cannot pair primaries.

    valkey-cli --cluster create 10.0.1.11:6379 \ 10.0.2.11:6379 10.0.3.11:6379 \ --cluster-replicas 0
  4. Add shard 1's replicas in zones B and C

    Name the primary by node ID so valkey-cli cannot choose another.

    PA=$(valkey-cli -h 10.0.1.11 CLUSTER MYID) valkey-cli --cluster add-node 10.0.2.12:6379 \ 10.0.1.11:6379 --cluster-replica \ --cluster-primary-id "$PA"
  5. Add the replicas of shards 2 and 3

    Zone B's primary gets replicas in C and A, and zone C's in A and B.

  6. Check that every shard spans three zones

    On 9.1 and later each shard should print 3. On 8.x, use the per-node loop below.

    valkey-cli -h 10.0.1.11 --json CLUSTER SHARDS \ | jq -r '.[] | [.nodes[] | ."availability-zone"] | unique | length'
  7. Rehearse a zone loss on staging

    Block one zone's client and cluster bus ports, then watch the other two.

    watch -n1 "valkey-cli -h 10.0.2.11 \ CLUSTER INFO | grep cluster_state"

Main risk: the layout holds only until the first failover moves a primary. Repeat step 6 after every failover, planned or not.

How should you lay out two zones instead of three?

With two zones, one of them is not survivable on its own. Three primaries means one zone holds two. Losing the other zone is routine, but losing the zone with two leaves one vote, so no replica can win an election and the survivors report cluster_state:fail.

The way out is manual. CLUSTER FAILOVER TAKEOVER promotes a replica "without any agreement with the rest of the cluster" and "violates the last-failover-wins principle". Run it only after confirming the other zone is down, not just cut off, or two primaries own the same slots and one side's writes are lost when the partition heals.

bash
# Zone A (two primaries) is confirmed down. On each zone B replica of an A primary:
valkey-cli -h 10.0.2.12 CLUSTER FAILOVER TAKEOVER
valkey-cli -h 10.0.2.13 CLUSTER FAILOVER TAKEOVER

Interpretation: each replica becomes a primary at once, with a config epoch it generates alone. cluster_state:ok returns once every slot has an owner.

The majority zone can also move under you. If one zone A primary fails alone, its zone B replica is promoted and zone B now holds two primaries. cluster-replica-no-failover yes on zone B replicas pins primaries to zone A; the 9.1.3 valkey.conf describes it for "multiple data center operations". The cost: an A primary whose A replica is also down gets no automatic failover.

Two zones and three zones, with three shards

Switch layouts to see which single-zone loss each survives without an operator

Two zones

ItemTwo zones (A and B)
Primaries per zoneA: 2, B: 1
Votes needed for a failover2 of 3
Zone A lost1 vote left: manual TAKEOVER in B
Zone B lost2 votes left: the zone A replica of P3 is promoted
Replicas per shardAt least one, in the other zone
Sentinel placementThe third Sentinel needs a third location
After any single failoverThe majority zone may flip from A to B

Three zones

ItemThree zones (A, B and C)
Primaries per zoneA: 1, B: 1, C: 1
Votes needed for a failover2 of 3
Zone A lost2 votes left: a replica of P1 in B or C is promoted
Zone B lost2 votes left: a replica of P2 in C or A is promoted
Replicas per shardTwo, one in each other zone
Sentinel placementOne Sentinel per zone, quorum 2
After any single failoverOne zone holds two primaries until you move one back

Rule of thumb: if you can run anything in a third zone, run a slot-owning primary there. Valkey Cluster has no arbiter role, because only primaries that own slots vote.

Which replica does Valkey Cluster promote, and what does 9.2 change?

In 9.1.3, each replica of a failed primary gains one rank for every sibling with a higher replication offset, and for every sibling with the same offset and a smaller node ID. Each rank delays its request for votes, so the freshest replica normally asks first. The zone is not an input: the new primary lands wherever the freshest copy was.

The 9.2.0-rc1 release notes add cluster-replica-priority (PR #2204), which names the problem: "failover doesn't account for the AZ". The fix is narrow. Offset still comes first, and priority only orders replicas with equal offsets, before the node ID. A lower value ranks better, the default is 0, and a non-default value is persisted in nodes.conf (#4454).

ini
# 9.2 release candidate only
# valkey.conf on replicas in the zone you want promoted first
cluster-replica-priority 0
# valkey.conf on replicas in the other zones
cluster-replica-priority 10
bash
grep "Start of election delayed" /var/log/valkey/valkey.log

Interpretation: on 9.1 the line reads Start of election delayed for N milliseconds (rank #R, primary rank #P, offset O). and the 9.2.0-rc2 source appends replica priority N. Rank #0 asks first, and a replica that is behind keeps a worse rank whatever its priority.

The PR does not say how often offsets tie; our reading is that ties are likely at low write rates and rare under a steady write load. A replica you never want promoted automatically, such as a far-region backup copy, takes cluster-replica-no-failover yes.

Release candidate, not GA

cluster-replica-priority exists only in 9.2.0-rc1 and rc2 as of November 2026. Its name, default and semantics can change before 9.2.0 GA, and 9.1 nodes ignore it.

How does Sentinel choose a replica across zones?

Sentinel uses the opposite order. The Sentinel documentation and compareReplicasForPromotion() in the 9.1.3 source sort by replica-priority first, then replication offset, then the smaller run ID. Replicas disconnected for more than down-after-milliseconds times 10, plus the time the primary has been down, are skipped, and priority 0 means never promote.

That gives real zone control at a price: a lower-priority replica wins even when a sibling in another zone has more of the stream, so steering by zone can lose more acknowledged writes. Sentinel ignores availability-zone, so priority is its only zone signal. Set it on every instance, primaries included, because a primary becomes a replica after a failover.

ini
# valkey.conf on the replica in the application's zone (us-east-1b)
replica-priority 50
# valkey.conf on every other instance, primaries included (100 is the default)
replica-priority 100

Sentinels follow the same majority rule as cluster primaries. Quorum only decides that the primary is down; the failover needs a majority of all Sentinels to elect a leader. The documentation recommends at least three Sentinels on machines that fail independently, such as "Virtual Machines executed on different availability zones".

ini
# sentinel.conf, one Sentinel in each of three zones
sentinel monitor cache-main 10.0.1.21 6379 2
bash
valkey-cli -p 26379 SENTINEL CKQUORUM cache-main
valkey-cli -p 26379 SENTINEL REPLICAS cache-main | grep -A1 -E 'slave-priority|slave-repl-offset'

Interpretation: a healthy group answers +OK 3 usable Sentinels. Quorum and failover authorization can be reached. SENTINEL REPLICAS still uses the field names slave-priority and slave-repl-offset; check the priority Sentinel sees for each zone's replica.

With two zones, the third Sentinel still needs a third location: two in zone A and one in zone B cannot elect a leader once zone A is gone. The documentation's examples run Sentinels on client boxes for this reason. On 9.0, check the ACL change in Sentinel on Valkey 9 before a zone rehearsal.

How do you check the zone layout with CLUSTER SHARDS?

On 9.1 and later, one command lists every node's role, health and zone. valkey-cli --json uses RESP3 by default, so each node arrives as a JSON object for jq. Nodes without a zone omit the field.

CLUSTER SHARDS with availability-zone on Valkey 9.1

Illustrative output: three shards, one primary and two replicas each, one node per zone

admin@bastion:~
$ valkey-cli -h 10.0.1.11 --json CLUSTER SHARDS \ | jq -r '.[] | .id[0:8] as $s | .nodes[] | [$s, .role, .health, ."availability-zone", .ip] | @tsv'3f9a6c1e master online us-east-1a 10.0.1.113f9a6c1e replica online us-east-1b 10.0.2.123f9a6c1e replica online us-east-1c 10.0.3.12b71d02a4 master online us-east-1b 10.0.2.11b71d02a4 replica online us-east-1c 10.0.3.13b71d02a4 replica online us-east-1a 10.0.1.12e05c9b73 master online us-east-1c 10.0.3.11e05c9b73 replica online us-east-1a 10.0.1.13e05c9b73 replica online us-east-1b 10.0.2.13

What to look for: one master per zone and three zones inside each shard. The field names follow the CLUSTER SHARDS reference, which lists the node-level availability-zone under 9.1.0; the IDs and addresses are invented.

For alerting, count online primaries per zone:

bash
valkey-cli -h 10.0.1.11 --json CLUSTER SHARDS | jq -r '
  [.[] | .nodes[] | select(.role == "master" and .health == "online")
   | (."availability-zone" // "unset")]
  | group_by(.) | map("\(.[0])\t\(length)") | .[]'

Interpretation: a zone whose count reaches half of cluster_size is a zone you cannot lose. An unset row is a primary without a zone.

On 8.0 and 8.1 the zone is not gossiped, so ask each node:

bash
valkey-cli -h 10.0.1.11 CLUSTER NODES \
  | awk '{split($2, a, "@"); print a[1], ($3 ~ /master/ ? "primary" : "replica")}' \
  | while read -r addr role; do
      az=$(valkey-cli -h "${addr%:*}" -p "${addr##*:}" CONFIG GET availability-zone | tail -1)
      echo "$addr $role ${az:-unset}"
    done

Interpretation: one line per node, such as 10.0.2.11:6379 primary us-east-1b. Add your authentication and TLS options to both calls. Client libraries parse CLUSTER SHARDS too, and one Go client broke on its 9.1 changes (see Valkey client breaking changes).

What should you do after the lost zone comes back?

Move a primary back. The cluster specification says a failed primary that rejoins will "reconfigure to replicate from the new primary", so the layout does not repair itself.

bash
# On the old P1, now a replica in zone A
valkey-cli -h 10.0.1.11 INFO replication | grep master_link_status
valkey-cli -h 10.0.1.11 CLUSTER FAILOVER

Interpretation: wait for master_link_status:up. A plain CLUSTER FAILOVER pauses writes on the primary and promotes the replica once it has the whole stream. The pause is bounded by cluster-manual-failover-timeout, 5000 ms by default and configurable since 8.1.

Then count primaries per zone again. Rehearse the sequence on staging by blocking the zone's ports, not by stopping one process, because the cluster bus decides the vote.

How do zone-aware clients use the availability-zone field?

The zone was added for clients, and reads are where it pays off. Valkey GLIDE's AZ affinity offers AZ_AFFINITY, which prefers replicas in the client's zone, and AZ_AFFINITY_REPLICAS_AND_PRIMARY, which tries a same-zone primary before other zones. Some managed services set the server zone for you; on self-managed nodes it comes from your valkey.conf.

python
from glide import GlideClusterClient, GlideClusterClientConfiguration, NodeAddress, ReadFrom

# Inside an async function
config = GlideClusterClientConfiguration(
    [NodeAddress(host="10.0.1.11", port=6379)],
    read_from=ReadFrom.AZ_AFFINITY,
    client_az="us-east-1a",
)
client = await GlideClusterClient.create(config)

Interpretation: reads go to a us-east-1a replica when one is available, and can be slightly stale because replication is asynchronous. Writes still go to the slot's primary in whatever zone it is.

Replication also crosses zones on every write. The replication topic documents repl-compression for links "such as between availability zones". It is a 9.2 release candidate setting (LZ4 in rc1, Zstandard added in rc2) and must be set on both primary and replica.

Production checklist for 3-AZ and 2-AZ placement

Three zones

  • Fewer than half of the slot-owning primaries in any zone: 1, 1, 1 for three shards. Avoid four shards.
  • Two replicas per shard, one in each other zone, added with --cluster-primary-id.
  • One Sentinel per zone with quorum 2, if you run Sentinel.

Two zones

  • An odd number of primaries, the majority in the zone you protect, and a written TAKEOVER runbook for losing that zone.
  • Optionally cluster-replica-no-failover yes on minority-zone replicas, and a third Sentinel in a third location.

Both

  • availability-zone in every valkey.conf, checked with INFO server.
  • Primaries per zone checked after every failover, with an alert at half of cluster_size.
  • A staging game day that blocks a zone's ports, then moves the primary back with CLUSTER FAILOVER.

Frequently asked questions

Does Valkey use the availability-zone setting during failover?

No. In every GA release up to 9.1.3, the zone is reported in INFO, HELLO and, from 9.1, CLUSTER SHARDS and CLUSTER SLOTS, but elections and replica placement ignore it. The 9.2 release candidate adds cluster-replica-priority, which you can set per zone, but it only breaks ties between replicas with equal replication offsets.

How many availability zones does a Valkey cluster need?

Three, if every single-zone loss should fail over without an operator. A failover needs votes from a majority of slot-owning primaries, so no zone may hold half of them or more. With two zones, one zone always holds the majority, and losing it needs a manual CLUSTER FAILOVER TAKEOVER in the surviving zone.

What is the difference between replica-priority and cluster-replica-priority?

replica-priority is read by Sentinel and outranks replication offset, so a preferred replica wins even when it is behind. cluster-replica-priority is a Valkey Cluster setting in the 9.2 release candidate that only orders replicas with the same offset. In both, a lower value is preferred, and replica-priority 0 means Sentinel never promotes that replica.

Where should Sentinels run in a two-zone Valkey deployment?

Put the third Sentinel outside both data zones, such as on an application host or a small instance in a third zone. A failover needs a majority of all Sentinels to elect a leader, so two Sentinels in one zone and one in the other cannot fail over when the zone with two is lost.

Plan a multi-AZ Valkey layout with JusDB

JusDB's Valkey high availability team can review your zone layout, replica priorities and Sentinel placement against the failure cases in this post, and plan a zone game day that fits your hosting.

Bring your Valkey versions, your CLUSTER SHARDS or SENTINEL REPLICAS output, and how nodes are assigned to zones today. Your team approves every production change.

Share this article

Database engineering notes

Articles like this one, in your inbox. No spam, unsubscribe anytime.

JusDB Team

Official JusDB content team

Keep reading

Moving a Multi-Database Valkey Instance into a 9.x Cluster

Move a Valkey instance that uses SELECT 1 to 15 into a 9.x cluster: keep or remap databases, copy each one, verify counts per database, and keep a way back.

Redis18 minNov 10, 2026
Read

Valkey Keyspace Notifications in Production: Expired Events, hexpired and Cluster Mode

Run Valkey keyspace notifications in production: why expired and hexpired events lag the TTL, how to subscribe on every cluster node, and when a stream is safer.

Redis20 minNov 10, 2026
Read

Valkey GLIDE in Production: AZ-Affinity Reads and Migrating from Legacy Clients

Configure Valkey GLIDE AZ-affinity reads on servers and clients, learn what GLIDE 2.5.3 does not support, and migrate from redis-py, Jedis, ioredis, or go-redis one service at a time.

Redis20 minNov 10, 2026
Read