RabbitMQ ACK vs NACK: acknowledgements, requeue & reject explained

January 6, 2026•9 min read•RabbitMQ tutorial

RabbitMQ ACK vs NACK: acknowledgements, requeue & reject explained

Quick answer: ACK vs NACK

RabbitMQ acknowledgements tell the broker what happened after a consumer receives a message. Use ACK when processing succeeds, NACK when processing fails, and choose whether failed messages should be requeued or discarded/dead-lettered.

In this guide, you'll learn how RabbitMQ ACK, NACK, reject, auto-ack, requeue, redelivery and prefetch work, with practical examples.

  • ACK: message was processed successfully
  • NACK + requeue=true: try delivering the message again
  • NACK + requeue=false: dead-letter or discard the message
  • Reject: like NACK, but for a single message
  • Auto ACK: RabbitMQ considers the message delivered immediately

What are RabbitMQ message acknowledgements?

When RabbitMQ delivers a message to a consumer, it needs to know when it's safe to remove that message from the queue. Without acknowledgments, RabbitMQ has two bad options: remove the message immediately (risking data loss if the consumer crashes) or never remove it (causing infinite redelivery).

Acknowledgments solve this by letting consumers tell RabbitMQ: "I'm done with this message, you can delete it."

A message that has been delivered but not yet acknowledged is called unacknowledged. It stays in the queue, invisible to other consumers, until the consumer acks it, nacks it, or disconnects.

RabbitMQ ACK vs NACK

ACK

An ACK confirms that the consumer successfully processed the message, so RabbitMQ can remove it from the queue for good.

channel.ack(msg);

NACK

A NACK tells RabbitMQ that the message could not be processed. The consumer decides what happens next through the requeue argument: put the message back in the queue, or remove it (and dead-letter it when a dead-letter exchange is configured).

channel.nack(msg, false, true);   // failed, try again
channel.nack(msg, false, false);  // failed, dead-letter or discard

Comparison table

MethodMeaningWhat happens to the message
ackSuccessfully processedRemoved from the queue
nack(..., false, true)Not processedRequeued
nack(..., false, false)Not processedDead-lettered or discarded
reject(..., true)Reject one messageRequeued
reject(..., false)Reject one messageDead-lettered or discarded

Use ack when processing succeeds. Use nack when processing cannot continue and you need to choose whether the message should be requeued or removed. Use reject when you only need to negatively acknowledge a single message.

RabbitMQ auto ACK vs manual acknowledgement

RabbitMQ's automatic acknowledgement mode, often called auto-ack and exposed as noAck: true in some client libraries, considers a message successfully delivered as soon as it is sent to the consumer. The broker doesn't wait for the consumer to finish processing, and the message is removed from the queue immediately.

channel.consume("orders", (msg) => {
  processOrder(msg);
}, { noAck: true });

This is the simplest mode, but it's risky:

  • If the consumer crashes mid-processing, the message is gone forever
  • If the consumer can't keep up, messages pile up in memory (no backpressure)
  • There's no way to tell RabbitMQ that processing failed

Use noAck: true only when losing messages is acceptable, like for non-critical metrics or logging where occasional data loss doesn't matter.

With manual acknowledgment, the consumer explicitly tells RabbitMQ when a message has been successfully processed. The message stays in the queue (marked as "unacknowledged") until the consumer sends an ack.

channel.consume("orders", (msg) => {
  try {
    processOrder(msg);
    channel.ack(msg);
  } catch (err) {
    console.error("Processing failed", err);
  }
});

If the consumer disconnects without acknowledging, RabbitMQ automatically requeues the message and delivers it to another consumer (or the same one when it reconnects).

This is the recommended mode for any production workload.

RabbitMQ NACK and requeue=true

What does requeue=true mean?

When you call nack or reject with requeue=true, RabbitMQ puts the unacknowledged message back into the queue so it can be delivered again. The message may be delivered to the same consumer or another consumer.

channel.nack(msg, false, true);

Every parameter of channel.nack(message, allUpTo, requeue):

ParameterValueMeaning
messagemsgThe message being negatively acknowledged
allUpTobooltrue: this message and all previous messages.
false: only this message.
requeuebooltrue: put the message back in the queue.
false: drop message.

NACK with requeue=true

Reject the message and requeue it for another delivery. RabbitMQ will attempt to place it back near its original position in the queue, depending on concurrent activity.

channel.consume("orders", (msg) => {
  try {
    processOrder(msg);
    channel.ack(msg);
  } catch (err) {
    channel.nack(msg, false, true);
  }
});

The third argument (true) means "requeue this message." Be careful with this pattern: if the message fails every time, it creates an infinite loop of redelivery. Always combine requeue with a retry strategy to avoid this.

NACK with requeue=false

Reject the message and remove it from the queue permanently:

channel.nack(msg, false, false);

If the queue has a dead-letter exchange configured, the message is routed there instead of being discarded. This is the recommended approach for handling poison messages.

RabbitMQ NACK vs reject

basic.reject and basic.nack can both reject a message and either requeue or remove it. The main practical difference is that nack can reject multiple unacknowledged messages at once using the multiple option, while reject works on a single message.

channel.reject(msg, true);   // reject and requeue
channel.reject(msg, false);  // reject and discard (or dead-letter)

nack was introduced later as an extension to AMQP and is generally preferred since it supports bulk operations.

ACKNACKReject
Processing succeeded✅❌❌
Requeue message❌✅✅
Remove/dead-letter❌✅✅
Multiple messages✅✅❌
Typical useSuccessFailure/batch handlingSingle-message rejection

Bulk NACK and multiple messages

The second argument to nack controls whether it applies to multiple messages. When set to true, it negatively acknowledges all unacknowledged messages up to and including the current one:

channel.nack(msg, true, false);

This is useful when a batch of messages depends on a shared resource that becomes unavailable.

The same option exists on ack, so you can acknowledge a whole batch with a single frame instead of one call per message:

channel.ack(msg, true);

Bulk acknowledgement reduces round trips, but it is all-or-nothing: every unacknowledged message delivered before the current one on that channel gets the same outcome. Use it only when the messages really share a fate.

RabbitMQ redelivered messages

A RabbitMQ message is marked as redelivered when it has previously been delivered to a consumer and is delivered again, for example after requeueing or when a consumer disconnects before acknowledging it.

When a message is requeued (via nack, reject, or consumer disconnect), RabbitMQ sets the redelivered flag to true. You can use this to detect messages that have been delivered before:

channel.consume("orders", (msg) => {
  if (msg.fields.redelivered) {
    console.warn("This message was redelivered");
  }
  processOrder(msg);
  channel.ack(msg);
});

This flag is useful for logging and debugging, but don't rely on it as a retry counter, it only tells you the message has been delivered more than once, not how many times.

Prefetch and unacknowledged messages

Prefetch count controls how many unacknowledged messages RabbitMQ will deliver to a consumer at once. Without it, RabbitMQ sends messages as fast as it can, which can overwhelm the consumer.

await channel.prefetch(10);
 
channel.consume("orders", (msg) => {
  processOrder(msg);
  channel.ack(msg);
});

With a prefetch of 10, RabbitMQ delivers up to 10 messages and then waits until some are acknowledged before sending more. This creates natural backpressure and ensures no single consumer hogs all the work.

Choosing a prefetch value

  • Too low (1–2): safe but slow, each message must be fully processed before the next one arrives
  • Too high (1000+): fast but risky, consumer memory spikes if processing is slow
  • Good starting point: 10–50, then tune based on your consumer's processing time

Common RabbitMQ ACK/NACK problems

Forgetting to ACK

If you consume with manual acknowledgment but never call ack, nack, or reject, messages stay in the "unacknowledged" state. Once the prefetch limit is reached, RabbitMQ stops delivering new messages to that consumer. The queue appears to stall.

ACKing twice

Acknowledging the same message twice throws a channel error and closes the channel. Always ensure your ack/nack logic runs exactly once per message.

Infinite requeue loops

Nacking with requeue (channel.nack(msg, false, true)) on a message that always fails creates an infinite redelivery loop. The message bounces between the queue and the consumer forever, burning CPU and blocking other messages. Use a retry pattern with a maximum retry count to prevent this.

Consumer failures

When a consumer crashes, its channel closes, or its connection drops, RabbitMQ requeues every message that consumer had not acknowledged yet. That is the behaviour you want, but it has two consequences.

First, a consumer that takes a long time to process a message can be dropped by a TCP or heartbeat timeout while it is still working. RabbitMQ assumes it is dead and requeues all its unacknowledged messages, so the work is done twice. Make sure your connection heartbeat interval is longer than your longest processing time, or break long tasks into smaller chunks.

Second, because a message can be delivered again after any consumer failure, processing must be idempotent. Deduplicate on a message ID or a business key so a redelivery doesn't charge a customer or send an email twice.

RabbitMQ ACK/NACK best practices

  • Use manual acknowledgement in production. Auto-ack is only for workloads where losing a message after delivery is acceptable.
  • Ack after the work is durable, not before. Acknowledge once the database write or the external call has committed, never at the start of the handler.
  • Ack exactly once per message. A double ack closes the channel, a missing ack stalls the consumer.
  • Prefer nack(msg, false, false) with a dead-letter exchange over blind requeueing for messages that fail deterministically.
  • Cap retries. Combine requeue with a retry pattern and a maximum attempt count so poison messages end up in a dead-letter queue instead of looping.
  • Set an explicit prefetch. It is the main backpressure knob between the broker and your consumers.
  • Make consumers idempotent, since any failure can turn into a redelivery.
  • Monitor unacknowledged messages. A spike usually means consumers are struggling. Use RabbitGUI to watch the unacknowledged message count per queue in real time and identify bottlenecks before they cascade. The same metrics are available through the HTTP API, see the RabbitMQ monitoring API article, and we cover operational habits around prefetch and acks in RabbitMQ best practices.

FAQ

What is ACK in RabbitMQ?

An ACK confirms that the consumer successfully processed the message, allowing RabbitMQ to remove it.

What is NACK in RabbitMQ?

A NACK negatively acknowledges a message and lets the consumer decide whether it should be requeued or removed/dead-lettered.

What does requeue=true do in RabbitMQ?

It tells RabbitMQ to put the negatively acknowledged message back into the queue for redelivery.

What is the difference between RabbitMQ NACK and reject?

Both negatively acknowledge messages, but NACK supports acknowledging multiple messages at once while reject handles a single message.

What happens if I don't ACK a RabbitMQ message?

The message remains unacknowledged. Once the consumer reaches its prefetch limit, RabbitMQ stops sending it additional messages. If the consumer/channel connection closes, unacknowledged messages can be requeued.

Should I use ACK or auto-ack?

Use manual ACK for workloads where reliable processing matters. Auto-ack is appropriate only when losing a message after delivery is acceptable.

Working with RabbitMQ?

See how RabbitGUI can make your everyday RabbitMQ workflows easier.
Available on Windows, Mac, and Linux.

Try RabbitGUIRabbitGUI screenshot

Read more RabbitMQ tutorials

RabbitMQ streams explainedRabbitMQ tutorialRabbitMQ streams explainedLearn what RabbitMQ Streams are, how they differ from traditional queues, and when to use them for high-throughput event streaming, replay, and fan-out.RabbitMQ ports: 5672, 15672, 25672 and more explainedRabbitMQ tutorialRabbitMQ ports: 5672, 15672, 25672 and more explainedRabbitMQ's default port is 5672 for AMQP. The Management UI uses 15672, clustering uses 25672 and 4369. Full ports table, Docker mappings and fixes for connection problems.What Is RabbitMQ?RabbitMQ tutorialWhat Is RabbitMQ?Learn what RabbitMQ is, how it works, and why it’s used in modern software architectures. Discover RabbitMQ’s benefits, key components, use cases, and how it enables reliable asynchronous communication.Setting up RabbitMQ with Docker and Docker ComposeRabbitMQ tutorialSetting up RabbitMQ with Docker and Docker ComposeA complete guide to running RabbitMQ in Docker containers, from quick start examples to advanced configuration options for production environmentsRabbitMQ Best PracticesRabbitMQ tutorialRabbitMQ Best PracticesA practical guide to RabbitMQ best practices covering queue design, message handling, connection management, monitoring, and production-readiness tips.RabbitMQ vs KafkaRabbitMQ tutorialRabbitMQ vs KafkaEverything you need to know about the differences between RabbitMQ and Kafka.