What Is AMQP 0.9.1? A Complete Guide to the Protocol

By | July 13, 2026

AMQP 0.9.1 is a message-oriented protocol that defines both a wire-level exchange format and a specific server model with exchanges, queues, bindings, and routing rules. It is best known as the native protocol of RabbitMQ, which is the most widely-deployed open source message broker in the world. Despite being called “legacy” in some OASIS documentation, AMQP 0.9.1 remains one of the most-used messaging protocols in production today, with an enormous ecosystem of client libraries, tooling, and community knowledge built around it.

This article covers what AMQP 0.9.1 actually is, why it looks so different from AMQP 1.0, how its server model works (exchanges, queues, bindings, routing keys, exchange types), how messages flow, delivery guarantees, security, and how it fits alongside other messaging protocols. It is written as a technical reference, and it is intentionally paired with the What Is AMQP 1.0 article in this category — the two protocols share a name but are otherwise different, and understanding one does not mean you understand the other.

AMQP 0.9.1 at a glance

PropertyDetail
Full nameAdvanced Message Queuing Protocol, version 0.9.1
StandardizedInformal specification (not an OASIS or ISO standard)
First released2008
ModelMessage queue protocol with mandated server model
TransportTCP; TLS is standard for encryption
EncodingBinary, frame-based, method-oriented
Server componentsExchanges, queues, bindings, routing keys (all defined by the protocol)
Exchange typesDirect, topic, fanout, headers
Delivery modelPublisher confirms + consumer acknowledgements
AuthenticationSASL (PLAIN, EXTERNAL, others via broker)
Broker required?Yes — the protocol assumes a broker with the mandated server model
Primary use casesEnterprise messaging, work queues, complex routing (via RabbitMQ)

The naming problem: AMQP 0.9.1 is not AMQP 1.0

Before going further, one point has to be stated clearly, because it causes real confusion. AMQP 0.9.1 and AMQP 1.0 are different protocols, not different versions of the same protocol. They share a name for historical reasons, but they are not wire-compatible, they define different things, and a client library written for one cannot talk to a broker that speaks only the other.

The version numbers suggest AMQP 1.0 is simply a newer version of AMQP 0.9.1, but that is misleading. AMQP 1.0 is a nearly complete redesign that removed the mandated server model, standardized only the wire protocol, and reoriented the protocol around peer-to-peer messaging rather than broker-mediated queue management. What you know about exchanges, queues, and bindings from AMQP 0.9.1 has no direct equivalent in AMQP 1.0’s protocol specification.

Why AMQP 0.9.1 still matters

Given that AMQP 1.0 was standardized by OASIS in 2012 and by ISO/IEC in 2014, and given that OASIS classifies AMQP 0.9.1 as a legacy specification, why is AMQP 0.9.1 still worth learning?

RabbitMQ. The single biggest reason is RabbitMQ. Despite RabbitMQ 4.0 (released in 2024) promoting AMQP 1.0 to a core protocol, AMQP 0.9.1 remains RabbitMQ’s default and most-documented protocol. The RabbitMQ ecosystem, tooling, tutorials, client libraries, and community knowledge are overwhelmingly built around AMQP 0.9.1. If you are working with RabbitMQ, you are almost certainly working with AMQP 0.9.1.

Simplicity for the covered scope. AMQP 0.9.1 has a well-defined server model built into the protocol, which means every AMQP 0.9.1 broker behaves the same way for the core operations. This is very different from AMQP 1.0, where the server model is unspecified and behavior varies significantly between brokers. For deployments where the exchange/queue/binding model fits the use case, AMQP 0.9.1’s specificity is a strength.

Continued development. New AMQP 0.9.1 client libraries and even new AMQP 0.9.1 brokers (LavinMQ, for example) continue to be built. This is not a protocol on its way out; it is a protocol with a specific, well-established niche that remains healthy.

The ecosystem. Extensive tooling has grown up around AMQP 0.9.1: management dashboards, monitoring integrations, testing tools, and library support in essentially every programming language. Migrating away from that ecosystem is expensive, and for most deployments there is no need to.

The AMQP 0.9.1 server model

The defining characteristic of AMQP 0.9.1 is that the protocol mandates a specific server model. Every AMQP 0.9.1 broker has the same conceptual components with the same protocol semantics. Understanding these components is the whole of understanding AMQP 0.9.1.

The four core concepts

Publisher (producer) — a client application that sends messages.

Exchange — the server-side entity that receives messages from publishers and routes them to queues according to routing rules. Publishers do not send messages directly to queues; they always send to an exchange.

Queue — the server-side buffer that stores messages until a consumer reads them. Messages sit in a queue in the order they were routed to it (with some exchange-type-specific and priority-based exceptions).

Consumer — a client application that reads messages from a queue and processes them.

Binding — the routing rule that connects an exchange to a queue, telling the exchange which messages should go to which queue.

The typical message path is: publisher → exchange → (bindings determine which queues) → queues → consumers. This is different from a pure pub/sub protocol like MQTT: there is an explicit intermediate stage (the exchange) where routing decisions happen, and there are explicit queues where messages wait.

Exchange types: the routing engine

The exchange decides where messages go based on its exchange type. AMQP 0.9.1 defines four standard exchange types, each with its own routing algorithm.

Direct exchange — messages are routed to queues whose binding key exactly matches the message’s routing key. This is the simplest form of routing: a message tagged with routing key error goes to queues bound to the exchange with binding key error. Direct exchanges are commonly used for work queues where different consumer pools handle different job types.

Topic exchange — messages are routed to queues whose binding key matches the message’s routing key according to a wildcard pattern. Binding keys can include * (matches exactly one word) and # (matches zero or more words), with words separated by dots. A message with routing key logs.error.database would match binding keys logs.error.*, logs.#, or #. Topic exchanges provide functionality similar to MQTT’s topic filters but with slightly different wildcard semantics.

Fanout exchange — messages are broadcast to every queue bound to the exchange, ignoring the routing key entirely. This is the simplest broadcast pattern: every queue that has been bound to a fanout exchange receives every message published to it. Fanout exchanges are used for scenarios where all consumers need every message.

Headers exchange — messages are routed based on the values of the message’s headers rather than its routing key. Bindings specify a set of header key-value pairs and a x-match value of either all (all headers must match) or any (at least one header must match). Headers exchanges are less commonly used but offer more flexible routing when the routing decision depends on multiple attributes.

Beyond the four standard types, RabbitMQ supports custom exchange types via plugins, which is one of the reasons AMQP 0.9.1’s routing is often considered more powerful than protocols where routing is fixed by the specification.

Routing keys and binding keys

Two related but distinct concepts:

  • The routing key is a string attached to a message when it is published, telling the exchange something about the message’s category.
  • The binding key is a string specified when a queue is bound to an exchange, telling the exchange which routing keys this queue is interested in.

For direct and topic exchanges, the exchange matches routing keys against binding keys to decide where messages go. For fanout exchanges, both are ignored. For headers exchanges, message headers replace the routing key in the decision.

Routing keys can be any UTF-8 string, though topic exchanges expect them to be dot-separated (logs.error.database) to interact meaningfully with wildcard patterns.

Queues, and what makes them different from topics

A queue in AMQP 0.9.1 is a first-class server-side entity that stores messages. This is different from MQTT topics, which are ephemeral routing labels that do not correspond to any stored buffer. AMQP 0.9.1 queues have properties, lifetimes, and behavior configured at declaration time:

  • Durable queues survive broker restarts (if their messages are also persistent).
  • Exclusive queues are usable by only one connection and are deleted when that connection closes.
  • Auto-delete queues are deleted when the last consumer unsubscribes.
  • Length limits can bound how many messages a queue holds, with configurable behavior when the limit is reached.
  • Time-to-live can bound how long messages live in the queue before being discarded.
  • Priority queues can order messages by priority instead of by arrival order.
  • Dead letter exchanges route rejected or expired messages elsewhere for handling.

This kind of first-class queue semantics is what makes AMQP 0.9.1 well-suited to work-queue patterns, where messages need to sit somewhere while consumers process them.

How a message flows

To make the model concrete, trace a single message through AMQP 0.9.1.

  1. Client declares infrastructure. Before publishing, the client typically declares the exchanges and queues it needs, and creates bindings between them. In AMQP 0.9.1, clients declare their own topology programmatically. If the entities already exist with matching parameters, declaration is a no-op; if they exist with different parameters, an error is raised.
  2. Client publishes a message. The client sends a Basic.Publish method with a target exchange, a routing key, message properties (persistence, priority, headers, and so on), and the message body. The message is sent to the exchange, not directly to any queue.
  3. Exchange routes the message. The exchange applies its type’s routing algorithm to the routing key (or headers, for a headers exchange), consults its bindings, and determines which queues should receive the message. It then places a copy of the message in each matching queue.
  4. Message sits in the queue. The message waits in the queue for a consumer. If the queue is empty and there are consumers waiting, the message is delivered immediately; if not, it queues up in order. Persistent messages on durable queues are written to disk; transient messages stay in memory.
  5. Consumer reads the message. A consumer that has subscribed to the queue receives the message via a Basic.Deliver method. The consumer processes the message.
  6. Consumer acknowledges. After successful processing, the consumer sends a Basic.Ack telling the broker the message has been handled. The broker removes it from the queue. If the consumer never acknowledges (because it crashes or times out), the broker re-queues the message for another consumer.
  7. Alternatively, consumer rejects. If the consumer cannot handle the message, it can send Basic.Nack or Basic.Reject to tell the broker to redeliver it (to another consumer) or discard it (possibly routing to a dead-letter exchange).

This flow is what makes AMQP 0.9.1 well-suited to reliable work-queue patterns. Every stage is explicit: the exchange routes, the queue stores, the consumer acknowledges. Messages are not lost when consumers fail, because unacknowledged messages are re-queued.

Delivery guarantees

AMQP 0.9.1 provides delivery guarantees through a combination of mechanisms.

Publisher confirms

By default, AMQP 0.9.1’s Basic.Publish method is fire-and-forget from the publisher’s perspective. The publisher does not know whether the broker actually received the message. For scenarios where publishers must know their message was safely accepted, AMQP 0.9.1 defines publisher confirms: the broker sends a Basic.Ack back to the publisher when the message has been safely stored (for persistent messages on durable queues, this means written to disk).

Publisher confirms are opt-in — a client must enable confirm mode with Confirm.Select before it takes effect — but once enabled, they provide the “at least once” guarantee from publisher to broker.

Consumer acknowledgements

By default, the broker considers a message delivered as soon as it sends it to the consumer. If the consumer crashes without processing, the message is lost. To avoid this, consumers can use explicit acknowledgement mode: the broker only removes the message from the queue after receiving an Basic.Ack from the consumer. If the consumer disconnects before acknowledging, the broker re-delivers the message (typically to a different consumer).

Together with publisher confirms, this gives “at least once” delivery: the publisher knows the broker received the message, and the broker knows the consumer processed it. There is no “exactly once” at the protocol level; deduplication is up to the application.

Persistence

For messages to survive broker restarts, three things must be true:

  • The queue must be declared as durable.
  • The message must be published as persistent (via the delivery_mode = 2 property).
  • The exchange must be durable (though most standard exchange types are durable by default).

If any of these is missing, the message can be lost when the broker restarts. This is a common source of unexpected message loss in AMQP 0.9.1 deployments: the queue was durable but the message was published as transient, or vice versa.

Transactions

AMQP 0.9.1 defines a transaction model that lets a publisher group multiple publishes into an atomic unit: either all the messages are accepted, or none are. Transactions are activated with Tx.Select and completed with Tx.Commit or Tx.Rollback. In practice, transactions are much slower than publisher confirms and are rarely used; publisher confirms are the recommended approach for reliability in modern deployments.

Flow control

AMQP 0.9.1 provides flow control through two mechanisms.

Consumer prefetch — the Basic.Qos method lets a consumer set a prefetch count, telling the broker not to send more than N unacknowledged messages to this consumer at a time. This is the primary tool for balancing message delivery: a slow consumer with prefetch of 1 gets one message at a time and cannot be overwhelmed; a fast consumer with a higher prefetch can process many messages concurrently.

Broker-side back-pressure — when the broker is under memory pressure or the queue is filling up faster than consumers can drain it, the broker can slow down publishers by delaying the acknowledgement of published messages (in confirm mode) or by explicitly refusing publishes. RabbitMQ’s flow-control mechanism uses this to prevent brokers from being overwhelmed.

Together, these give AMQP 0.9.1 practical control over message flow at both the sender and receiver ends of the message path.

Security

AMQP 0.9.1 relies on the standard combination of TLS for transport security and SASL for authentication.

TLS — the connection can be upgraded to TLS, encrypting all traffic between the client and the broker. This is the standard practice for anything beyond local development.

SASL — authentication happens as part of the connection setup, using SASL mechanisms. The most common mechanisms are PLAIN (username and password, safe only over TLS) and EXTERNAL (authentication is provided by TLS client certificates). RabbitMQ supports several additional SASL mechanisms as plugins.

Authorization — access control is not defined by the AMQP 0.9.1 protocol; it is implemented by the broker. RabbitMQ, for example, has a granular permission system that controls which users can configure, write to, or read from which exchanges and queues.

Common containers and libraries

While AMQP 0.9.1 is primarily associated with RabbitMQ, several brokers speak it:

  • RabbitMQ — the reference implementation and by far the most widely-deployed AMQP 0.9.1 broker.
  • LavinMQ — a newer, lightweight AMQP 0.9.1 broker written in Crystal, focused on high performance.
  • Apache Qpid — Qpid brokers historically supported AMQP 0.9.1, though 1.0 is now the primary focus.
  • Various embedded implementations for testing or in-process messaging.

AMQP 0.9.1 client libraries exist for essentially every programming language, in most cases either developed by the RabbitMQ team or based on their reference specification. The most commonly used libraries include:

  • Java — the official RabbitMQ Java client.
  • Python — Pika, or the official RabbitMQ Python client.
  • .NET — the RabbitMQ .NET client.
  • Node.js — amqplib.
  • Go — streadway/amqp or newer forks.
  • Ruby — Bunny.
  • PHP — php-amqplib.
  • C/C++ — rabbitmq-c and others.
  • Rust — lapin, amiquip, and others.

The consistency of client libraries across languages is one of the practical advantages of AMQP 0.9.1’s specific server model: because every broker behaves the same way, the same client-side abstractions work everywhere.

AMQP 0.9.1 versus AMQP 1.0

Since the two protocols share a name, it is worth being explicit about how they differ. The relationship is not one of successor and predecessor; it is one of two distinct protocols that happen to share a name.

AspectAMQP 0.9.1AMQP 1.0
StandardizationInformal specOASIS Standard, ISO/IEC 19464
ModelMandated server model (exchanges, queues, bindings)Wire protocol only; no server model
Broker requiredYesNo
RoutingDefined by exchange typesNot defined by protocol
Delivery outcomesAck / Nack / RejectAccepted / Rejected / Released / Modified
SettlementImplicitConfigurable per link
Primary use caseRabbitMQ-based enterprise messagingCross-vendor interoperability, cloud messaging
EcosystemVery large (RabbitMQ)Growing, spread across many vendors

Choose AMQP 0.9.1 when: you are working with RabbitMQ or planning to; you want the specificity and consistency of a mandated server model; the ecosystem and community knowledge around AMQP 0.9.1 fit your team; the exchange/queue/binding model matches your messaging needs.

Choose AMQP 1.0 when: you need cross-vendor interoperability across multiple broker types; you are working with Azure Service Bus, IBM MQ, or another AMQP 1.0-native service; your organization requires an ISO or OASIS-standardized protocol; the delivery-state and settlement flexibility of AMQP 1.0 fits your needs.

Both are legitimate choices for different situations. Neither is universally better.

AMQP 0.9.1 versus MQTT

Since MQTT and AMQP are often compared, a brief orientation here is useful.

MQTT is a lightweight publish/subscribe protocol designed for IoT and constrained devices. It has a small conceptual footprint (topics, wildcards, three QoS levels) and is designed to run efficiently on tiny hardware. It does not have exchanges, first-class queues, or explicit routing rules — routing is entirely by topic matching.

AMQP 0.9.1 is a heavier, more feature-rich protocol designed for enterprise messaging. It has exchanges with multiple routing algorithms, first-class queues with rich behavior, and explicit delivery guarantees. It is not designed for constrained devices.

Choose MQTT for IoT, constrained hardware, high connection counts, and simple pub/sub. Choose AMQP 0.9.1 for work queues, complex routing (especially patterns that need headers-based or exchange-to-exchange routing), and enterprise messaging where the RabbitMQ ecosystem fits. The MQTT vs AMQP comparison article in the MQTT category covers this in detail.

Common patterns in AMQP 0.9.1

A few messaging patterns are so common in AMQP 0.9.1 deployments that they are worth recognizing.

Work queue. Publisher sends jobs to a queue via a direct or default exchange. Multiple consumers subscribe to the queue and each processes a message in turn. This is the classic AMQP 0.9.1 pattern and one of the most-used messaging idioms in enterprise systems.

Publish/subscribe (fanout). Publisher sends a message to a fanout exchange. Every queue bound to the exchange receives a copy. Each consumer has its own queue and processes messages independently.

Routing (direct). Publisher tags messages with a routing key like severity=error. Subscribers create queues that bind to the exchange with specific routing keys (error, warning, info), receiving only the messages that match.

Topic routing. Publisher tags messages with a hierarchical routing key like logs.errors.database. Subscribers bind queues to a topic exchange with wildcard patterns (logs.errors.*, logs.#, and so on), receiving matching messages.

RPC (request/reply). Publisher sends a request message with a reply-to property specifying a queue the reply should go to, and a correlation-id matching request to reply. The consumer processes the request and publishes the reply to the specified queue. This gives synchronous-feeling calls over an asynchronous protocol.

Dead letter handling. Messages that are rejected, expire, or exceed queue limits are routed to a dead letter exchange for special handling — logging, monitoring, or retry logic. This is a first-class feature of AMQP 0.9.1 and one of the reasons it is well-suited to reliability-focused deployments.

Frequently asked questions

What is AMQP 0.9.1? AMQP 0.9.1 is a message-oriented protocol that defines both a wire-level exchange format and a specific server model with exchanges, queues, bindings, and routing rules. It is best known as the native protocol of RabbitMQ.

Is AMQP 0.9.1 the same as AMQP 1.0? No. Despite the shared name, AMQP 0.9.1 and AMQP 1.0 are different protocols. They are not wire-compatible. AMQP 0.9.1 has a mandated server model; AMQP 1.0 does not. See the What Is AMQP 1.0 article for the other protocol.

Is AMQP 0.9.1 an OASIS or ISO standard? No. AMQP 0.9.1 is an informal specification maintained outside the OASIS process. Despite this, it is widely deployed. AMQP 1.0 is the OASIS-standardized (and ISO/IEC 19464) version.

Is AMQP 0.9.1 deprecated? No. Although OASIS classifies AMQP 0.9.1 as legacy in favor of AMQP 1.0, it remains very actively used. RabbitMQ continues to develop it, new brokers like LavinMQ are being built for it, and its ecosystem is one of the largest in messaging.

What is an exchange in AMQP 0.9.1? An exchange is the server-side component that receives messages from publishers and routes them to queues according to bindings and its own type-specific routing algorithm. AMQP 0.9.1 defines four standard exchange types: direct, topic, fanout, and headers.

What is a binding? A binding is a rule that connects an exchange to a queue, telling the exchange which messages should be routed to that queue. For direct and topic exchanges, bindings include a binding key that is matched against message routing keys.

What port does AMQP 0.9.1 use? Port 5672 for plain (unencrypted) connections and 5671 for connections over TLS. This is the same port that RabbitMQ also uses for AMQP 1.0 when that protocol is enabled.

Do I have to use RabbitMQ for AMQP 0.9.1? No, but in practice most deployments do. Alternative AMQP 0.9.1 brokers exist (LavinMQ is a notable modern example), but RabbitMQ has by far the largest ecosystem.

Does AMQP 0.9.1 guarantee exactly-once delivery? No. AMQP 0.9.1 provides at-least-once delivery through publisher confirms and consumer acknowledgements. Exactly-once semantics require application-level deduplication.

Should I use AMQP 0.9.1 or AMQP 1.0? Use AMQP 0.9.1 if you are on RabbitMQ, if the exchange/queue/binding model fits your use case, or if the ecosystem of tooling and community knowledge is valuable to your team. Use AMQP 1.0 if you need cross-vendor interoperability, if you are on Azure Service Bus or similar, or if you need an ISO/OASIS-standardized protocol. Both are valid choices.

Author: Zakaria El Intissar

I've spent 13 years in power system automation, electrical protection, and SCADA communication, as an automation and industrial computing engineer. ScadaProtocols.com is where I turn what I've learned on site into plain guides and working tools — so other engineers can decode, analyze, and troubleshoot industrial communication protocols without the guesswork.