How it works
MQTT / AMQP clients ──> MQ Gateway ──> NATS
├─ subjects (QoS 0, presettled)
├─ streams (QoS 1/2, unsettled)
└─ KV buckets (sessions, retained)
Not a broker
The gateway translates MQTT and AMQP into NATS and keeps nothing of its own that outlives it. NATS routes every message, enforces every permission, and stores whatever has to be kept. As a result, any gateway can serve any client, and running more gateways adds capacity without a new consistency problem.
You create the streams and buckets. The gateway never creates, changes or
deletes one, because retention, replicas and size limits are capacity
decisions for whoever runs NATS. At start-up the gateway checks that what
its config names exists and can do the job. mq-gateway generate prints
those streams and buckets, and mq-gateway check verifies them.
Each client is a NATS user
Every MQTT or AMQP connection gets its own NATS connection, as a NATS user. The listener the client connects to decides which user:
- passthrough: the client's username and password are its NATS credentials.
- fixed: every client on the listener is one configured NATS user. Use this for devices that can't hold a credential.
NATS then accepts or refuses the credential and applies that user's permissions to everything the client does. The gateway has no permission system of its own to keep in step. A client is served in its user's NATS account, so accounts isolate fleets from each other.
Delivery
| Client sends | Travels as | Acknowledged when |
|---|---|---|
| MQTT QoS 0, AMQP presettled | A core NATS message | Never: at most once |
| MQTT QoS 1 or 2, AMQP unsettled | A message stored in a stream | The stream has stored it |
Stored delivery only works on subjects you bind to a stream in the config. A QoS 1 or 2 publish, or an unsettled AMQP transfer, to anything else is refused, not downgraded. A downgrade would leave the client waiting on an acknowledgement that never comes, and would hide a missing binding.
Every message is also an ordinary NATS message on its subject. NATS services publish and subscribe on the same subjects, and MQTT, AMQP and NATS clients all see each other's messages.
On the way out:
- An MQTT subscription at QoS 1 or 2 reads from its own JetStream consumer. The client gets each message once, at the lower of the published and the granted QoS.
- AMQP receivers on a bound address share one consumer by default, so each
message goes to one receiver, as with a queue. A receiver that asks for
topicor copy mode gets its own consumer. - Anything else is a plain NATS subscription.
Messages arrive in the order the stream holds them. After a failure, such as a lost connection or a gateway that died, a message can be delivered again, and that copy can arrive after messages that came later. A client that must not act on a message twice should discard duplicates, using an ID its publisher puts in the payload or a property.
Sessions and retained messages
Name a sessions bucket to get MQTT persistent sessions. A client that reconnects, to this gateway or another one, gets its subscriptions back and everything stored while it was away. QoS 0 messages aren't queued while a client is offline.
Name a retained bucket to keep MQTT retained messages. A new subscription receives the latest retained message on each matching topic.
Without these buckets, every session is clean and the gateway ignores the RETAIN flag.
Several gateways
Gateways that share a sessions bucket act as one, provided each has its
own --id:
- A client that reconnects to another gateway resumes its session there, and its old connection is closed.
- When a gateway dies without closing its connections, the others end its
sessions and publish their wills after two to three
mqtt.sessions.sweepintervals (2–3 minutes by default). - In lame duck mode, a gateway stops accepting new clients and closes its connections gradually. Each session is saved on the way out, so clients resume on another gateway with nothing lost.
Wills still go out when a gateway stops, because to the client it is a lost connection. A v5 client can avoid that during a planned restart. It needs a persistent session, with a Session Expiry Interval and a Will Delay Interval both longer than it takes to reconnect.
When things fail
- QoS 1 or 2 to a topic that no binding stores: the gateway refuses the publish. Add a binding, or publish at QoS 0.
- The stream does not acknowledge the message in 5s: the gateway
disconnects an MQTT client and sends no acknowledgement. The client
sends the message again when it reconnects. An AMQP client gets
rejectedand keeps its link. - The NATS user of the client does not have permission: NATS refuses that publish or subscription.
- A stream reaches its consumer limit: each MQTT session at QoS 1 or 2
holds one consumer on each stream that it reads. The
max_consumerslimit of the stream sets how many of these sessions it can serve. The default is 1,000. Past that limit, the gateway refuses new subscriptions. - The gateway stops: the gateway disconnects its clients. The clients reconnect to another gateway.
- A NATS server stops: the NATS connections of the clients move to the other servers. Most clients stay connected.
Errors lists the code that each client sees.