# Architecture (/connectors/mqtt/concepts/architecture)



The KubeMQ **MQTT connector** is an embedded MQTT broker that runs inside kubemq-server. It
speaks the standard MQTT protocol (3.1.1 and 5.0) on plain port **1883**, TLS port
**8883**, and WebSocket port **8083** (path `/`). The connector is &#x2A;*opt-in (disabled by
default)** — enable it with `CONNECTORSMQTT_ENABLE=true` (Docker) or `spec.mqtt.enabled: true`
(Kubernetes). Any standard MQTT client connects to it with only a broker-address change — no
code rewrite, no library swap, no KubeMQ SDK.

Unlike the RabbitMQ (AMQP 0-9-1) connector — which bridges onto exactly one KubeMQ
primitive — the MQTT connector bridges onto **all five** KubeMQ patterns: Events,
Events-Store, Queues, Commands, and Queries. The **first segment of the topic** selects
which pattern a publish or subscribe is bound to. That single fact drives the whole mental
model.

## Protocol stack [#protocol-stack]

A client connection terminates at the embedded broker. A bridge hook intercepts the MQTT
CONNECT / PUBLISH / SUBSCRIBE packets, the topic mapper resolves each topic to a KubeMQ
`(pattern, channel)` pair, and the request is dispatched to KubeMQ's core service, which
hands it to the message broker. From there it reaches consumers on any KubeMQ transport.

<Mermaid
  chart="`
graph TB
APP[&#x22;MQTT client<br/>tcp :1883 / tls :8883 / ws :8083&#x22;]
BR[&#x22;Embedded MQTT broker&#x22;]
HOOK[&#x22;Bridge hook<br/>CONNECT / PUBLISH / SUBSCRIBE&#x22;]
MAP[&#x22;Topic mapper<br/>prefix → pattern, '/' → '.'&#x22;]
CORE[&#x22;KubeMQ core service<br/>Events · Store · Queues · RPC&#x22;]
BROKER[&#x22;Message Broker&#x22;]
OTHER[&#x22;gRPC / REST / other connectors&#x22;]

APP --> BR
BR --> HOOK
HOOK --> MAP
MAP --> CORE
CORE --> BROKER
BROKER -. &#x22;also bridged to&#x22; .-> OTHER

class APP client
class BR,HOOK,MAP connector
class CORE,BROKER broker
class OTHER client
`"
/>

*The embedded broker terminates the MQTT connection; the bridge hook and topic mapper translate each packet onto a KubeMQ pattern and channel, and the message broker fans it out to every other KubeMQ transport.*

## How MQTT maps to KubeMQ [#how-mqtt-maps-to-kubemq]

The first topic segment (the **prefix**) selects the KubeMQ pattern. The remaining segments
become the KubeMQ channel, with `/` translated to `.`.

<Mermaid
  chart="`
graph LR
TOPIC[&#x22;MQTT topic<br/>&lt;prefix&gt;/&lt;rest&gt;&#x22;]
E[&#x22;events/&#x22;]
ST[&#x22;store/&#x22;]
Q[&#x22;queues/&#x22;]
C[&#x22;commands/&#x22;]
QY[&#x22;queries/&#x22;]
BROKER[&#x22;Message Broker&#x22;]

TOPIC --> E
TOPIC --> ST
TOPIC --> Q
TOPIC --> C
TOPIC --> QY

E -- &#x22;Events&#x22; --> BROKER
ST -- &#x22;Events-Store&#x22; --> BROKER
Q -- &#x22;Queues&#x22; --> BROKER
C -- &#x22;Commands (RPC)&#x22; --> BROKER
QY -- &#x22;Queries (RPC)&#x22; --> BROKER

class TOPIC client
class E,ST,Q,C,QY connector
class BROKER broker
`"
/>

*The topic prefix selects the KubeMQ pattern; the remaining segments form the channel with `/` translated to `.`.*

| MQTT topic / filter          | KubeMQ pattern                         | Direction                             | Example topic                 | KubeMQ channel |
| ---------------------------- | -------------------------------------- | ------------------------------------- | ----------------------------- | -------------- |
| `events/<ch>`                | **Events**                             | publish + subscribe                   | `events/site1/temp`           | `site1.temp`   |
| `store/<ch>`                 | **Events-Store**                       | publish + subscribe (StartNewOnly)    | `store/site1/temp`            | `site1.temp`   |
| `queues/<ch>`                | **Queues**                             | **publish only** (produce)            | `queues/jobs/email`           | `jobs.email`   |
| `commands/<ch>`              | **Commands (RPC)**                     | **publish only**, MQTT 5.0 only       | `commands/svc/reboot`         | `svc.reboot`   |
| `queries/<ch>`               | **Queries (RPC)**                      | **publish only**, MQTT 5.0 only       | `queries/svc/status`          | `svc.status`   |
| `$share/<group>/queues/<ch>` | **Queues**                             | **subscribe only** (consume), QoS ≥ 1 | `$share/g1/queues/jobs/email` | `jobs.email`   |
| `$reply/<clientID>/<suffix>` | broker-local                           | subscribe (own namespace only)        | `$reply/client1/inbox`        | not routed     |
| *(prefixless)*               | `DefaultPattern` (`events` by default) | publish + subscribe                   | `site1/temp`                  | `site1.temp`   |

Resolution rules:

* **Translation rule:** topic path separators `/` become KubeMQ channel dot separators `.`.
  `events/site1/sensors/temp` → channel `site1.sensors.temp`.
* **Prefixless topics** route to the configured `DefaultPattern` (`events` by default;
  `store` or `none` are the alternatives). With `none`, a prefixless publish returns PUBACK
  `0x90` and a prefixless subscribe returns SUBACK `0x8F`.
* **A literal `.` inside a topic segment is not escaped** — it passes through unchanged and
  conflates with `/`. Both `events/a.b/c` and `events/a/b/c` map to channel `a.b.c`. Avoid
  dots in topic segments.

See [Topic grammar](/connectors/mqtt/reference/topic-grammar) for the master table and
[Topic mapping](/connectors/mqtt/concepts/topic-mapping) for narrative guidance.

## Wildcard translation [#wildcard-translation]

Wildcards are permitted **only** on Events subscriptions. A wildcard subscribe on any other
pattern returns SUBACK `0xA2`.

| MQTT wildcard      | KubeMQ wildcard | Constraint                |
| ------------------ | --------------- | ------------------------- |
| `+` (single level) | `*`             | any segment position      |
| `#` (multi level)  | `>`             | must be the final segment |

For example, `events/site1/+` subscribes to the channel filter `site1.*`, and `events/#`
subscribes to `>`. A `store/#` subscribe is rejected with SUBACK `0xA2` because wildcards
are Events-only.

<Callout type="info">
  **Overlapping wildcard filters multiply delivery.** Each distinct subscribe filter creates
  an independent bridge registry entry. If several of a client's subscriptions match the same
  published message, the client receives one copy per matching entry — there is no cross-entry
  deduplication. Subscribing to `#`, `events/leak/x`, and `events/#` at once delivers **three
  copies** of a publish to `events/leak/x`.
</Callout>

## The bridge hook and topic mapper [#the-bridge-hook-and-topic-mapper]

The embedded broker delegates every protocol decision to a single **bridge hook**:

* **CONNECT** — authenticates the connection (MQTT username / password; the identity is the
  ClientID) and enforces the protocol-version floor. See
  [Authentication](/connectors/mqtt/how-to/authentication).
* **PUBLISH** — the topic mapper resolves the prefix to a pattern and channel; the hook
  dispatches the message to the KubeMQ core (Events / Events-Store / Queues produce, or an
  RPC request for Commands / Queries) and translates the result into a PUBACK reason code.
* **SUBSCRIBE** — the hook registers the filter in the subscription registry (with wildcard
  fan-out for Events), or wires a Queue consumer for a `$share/<group>/queues/<ch>` filter,
  and returns the SUBACK reason codes.

Two dedicated bridges handle the stateful patterns: a **queue bridge** drives shared-
subscription polling, PUBACK-driven acknowledgment, and redelivery for Queues; an **RPC
bridge** dispatches Commands / Queries requests, routes the response back over the client's
response topic, and tracks pending requests against `RpcMaxPending`.

### User Properties ↔ KubeMQ Tags [#user-properties--kubemq-tags]

MQTT 5.0 User Properties map bidirectionally to KubeMQ message Tags. This mapping is **MQTT
5.0 only** — MQTT 3.1.1 has no user-properties, so nothing is carried in either direction
over a v3.1.1 connection.

| Direction                      | MQTT side         | KubeMQ side | Notes                                       |
| ------------------------------ | ----------------- | ----------- | ------------------------------------------- |
| Inbound (publish → KubeMQ)     | `Properties.User` | `Tags` map  | copied 1:1; duplicate keys: last-wins       |
| Outbound (KubeMQ → subscriber) | `Properties.User` | `Tags` map  | injected on delivery to v5 subscribers only |

Per-message caps apply to Events, Events-Store, and Queues publishes: **32 properties** and
**4096 bytes total** (all keys + values). Exceeding either cap rejects the message — PUBACK
`0x97` on v5, or a silent drop on v3.1.1.

## Cross-protocol interop [#cross-protocol-interop]

The KubeMQ core service is the shared message bus for all KubeMQ connectors, so MQTT
interoperates transparently with every other transport. An MQTT publish to `events/it/cross`
is received by a gRPC `SubscribeEvents` on channel `it.cross`, and vice-versa. The same
holds for Events-Store, Queues, Commands, and Queries — any connector (gRPC, REST,
CloudEvents, MQTT) can interoperate on the same channels.

<Mermaid
  chart="`
graph LR
MQTT[&#x22;MQTT client<br/>events/it/cross&#x22;]
GRPCCLIENT[&#x22;gRPC / REST client<br/>channel: it.cross&#x22;]
BROKER[&#x22;Message Broker&#x22;]

MQTT -- &#x22;publish&#x22; --> BROKER
BROKER -- &#x22;subscribe&#x22; --> GRPCCLIENT
GRPCCLIENT -- &#x22;publish&#x22; --> BROKER
BROKER -- &#x22;subscribe&#x22; --> MQTT

class MQTT,GRPCCLIENT client
class BROKER broker
`"
/>

*The same KubeMQ channel backs both connectors, so an MQTT client and a gRPC/REST client interoperate transparently.*

## Related [#related]

<Cards>
  <Card title="Topic grammar" href="/connectors/mqtt/reference/topic-grammar" description="The master topic grammar — prefixes, wildcards, $share queue consume, and $reply." />

  <Card title="Capabilities" href="/connectors/mqtt/reference/capabilities" description="The full CONNACK capability set, forced values, and the per-message property caps." />

  <Card title="Events" href="/connectors/mqtt/how-to/events" description="Fire-and-forget pub/sub over MQTT — wildcards and User-Properties as Tags." />

  <Card title="Reason codes" href="/connectors/mqtt/reference/reason-codes" description="The PUBACK / SUBACK / CONNACK reason codes the connector returns and what triggers each." />
</Cards>
