RabbitMQ Quorum Queues: When Replicated Messaging Is Worth the Latency
Quorum queues use Raft consensus to replicate RabbitMQ messages across nodes. Here's how to declare one, prove failover works, and decide when the latency trade-off is worth it.
04 Sept 2025, 23:10 UTC

If a RabbitMQ node dies while holding your queue, what happens to the messages? With a classic queue on a single node, the answer is uncomfortable: unacknowledged messages on that node are unavailable until it comes back, and if the disk is gone, so are they. Quorum queues exist to make that answer boring instead: the message is on multiple nodes, a majority confirmed the write, and one node dying is a non-event.
This post covers what quorum queues actually do, a concrete declaration and failover setup, and the honest trade-offs — because they are not the right default for every workload.
What a quorum queue actually is
A quorum queue is a replicated, durable queue type built on the Raft consensus protocol. Instead of one node owning the queue, a small group of nodes (the quorum) each hold a replica. A write is only confirmed to the publisher after a majority of replicas have it on disk. One replica acts as leader and handles ordering; if the leader disappears, the remaining replicas elect a new one automatically.
This replaces classic mirrored queues, which are deprecated and scheduled for removal. Mirroring tried to replicate whole queue state with a synchronization mechanism that was prone to split-brain and painful recovery. Quorum queues replicate only the queue's contents and lean on Raft's well-understood leader election, which is why the RabbitMQ team made them the recommended replicated queue type.
Declaring one: a concrete example
The queue type is fixed at declaration time via the x-queue-type argument. You cannot convert an existing classic queue in place — migration means declaring a new quorum queue and moving producers and consumers over.
Declaring from a client (AMQP, any major library):
queue_declare(
queue="orders",
durable=true,
arguments={"x-queue-type": "quorum"}
)Or from the server side with a policy, which is often cleaner for fleets of queues:
rabbitmqctl set_policy quorum-orders "^orders\." \
'{"queue-type":"quorum"}' --apply-to queuesRun this on any node in the cluster; policies propagate. Then verify the declaration did what you think it did:
rabbitmqctl list_queues name type leader membersYou should see orders with type quorum and a member list matching your replica count. The management UI shows the same under the queue's "Features" column.
On a 3-node cluster the default replication factor is the cluster size, so all three nodes hold a replica. On larger clusters, cap it with x-quorum-initial-group-size (for example 3 or 5) — replicating every queue to every node in a 10-node cluster wastes disk and slows writes for no availability gain.
For the full safety story, pair the declaration with:
- Publisher confirms on the producer, so you know when a majority has persisted the message.
- Manual acknowledgements on consumers, so a crashed consumer doesn't lose in-flight work.
- A delivery limit and dead-letter exchange, so a poison message doesn't redeliver forever (quorum queues track delivery counts, which makes this enforceable).
The failover drill that proves it works
Configuration claims are cheap; the failover drill is where you find out. On a test cluster:
- Publish a few hundred messages with confirms enabled.
- Identify the leader node from
rabbitmqctl list_queues name leader. - Stop RabbitMQ on that node (
rabbitmqctl stop_appor kill the service). - Re-run the listing: a new leader should appear within seconds.
- Consume the queue from scratch and confirm every confirmed message is present.
Expect a brief window where publishes to that queue fail or block during election — clients should retry. What you should not see is any confirmed message missing.
The trade-offs, stated plainly
Throughput and latency. Majority-acknowledged disk writes cost more than a single-node write. For high-volume, transient telemetry where losing a burst is acceptable, a classic queue will be faster and simpler. Measure both with your real payload sizes before deciding.
Odd numbers only. A quorum needs a majority, so a 2-node "cluster" tolerates zero failures for writes — it adds overhead without adding availability. Use 3 or 5 replicas.
Feature compatibility. Some classic-queue features are unsupported or behave differently on quorum queues: non-durable and exclusive queues are out, transient (non-persistent) messages are rejected, and per-message TTL support has varied by version. Behavior changed across the 3.8.x line and later releases, so check the docs for the exact version you run before assuming a feature works.
Immutability. The queue type can never change after declaration. If you declare classic today and want quorum later, plan for a migration with a new queue name or a blue-green cutover.
The decision rule
Use quorum queues when losing acknowledged messages or tolerating a node outage matters more than raw throughput — orders, payments, task dispatch. Use classic queues when messages are cheap to regenerate and speed is the point. Either way, declare the type deliberately, run the failover drill once, and write down what you observed. That drill is the difference between "replicated" as a configuration value and replication you can actually trust.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.