# Capabilities (/connectors/mqtt/reference/capabilities)



This reference lists every capability the KubeMQ MQTT connector advertises to clients —
including the values that are **forced** regardless of configuration — plus its
configurable limits, protocol-version support, session semantics, and the limitations you
must design around. Use it to decide which MQTT client features are safe to rely on and
which ones are refused or silently dropped.

## Forced (non-configurable) capabilities [#forced-non-configurable-capabilities]

These flags are hardcoded in the connector's `CONNACK` and **cannot** be changed at
runtime. They are the three load-bearing capability bits an MQTT 5.0 client reads at
connect time, plus the PUBACK-property rule:

| Capability                   | Wire value | Effect                                                                                                                                                                                                                                     |
| ---------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `RetainAvailable`            | `0`        | Retain is **disabled**. A retained PUBLISH at runtime is silently dropped (success PUBACK `0x00`); a `Will-retain=true` CONNECT is rejected with CONNACK `0x9A`. See the [retain gotcha](#gotcha-1-retain-is-silently-dropped-at-runtime). |
| `SharedSubAvailable`         | `1`        | Required for `$share/<group>/queues/<ch>` queue consumption.                                                                                                                                                                               |
| `WildcardSubAvailable`       | `1`        | Required for Events wildcard subscriptions (`+`, `#`).                                                                                                                                                                                     |
| `NoInheritedPropertiesOnAck` | `true`     | PUBACK never echoes the PUBLISH user properties back to the sender. Every successful QoS 1 PUBACK is property-free.                                                                                                                        |

<Callout type="warn">
  **Retain is silently dropped (`RetainAvailable=0`).** The connector advertises that retain
  is unavailable, but if a client sends a retained PUBLISH anyway, the retain flag is
  stripped, the message is **dropped**, and the **PUBACK still succeeds** (`0x00`) — the
  sender gets no wire-level indication. The only retain-related error is a `Will-retain=true`
  CONNECT, which is rejected with CONNACK `0x9A`. There is no durable subscription support.
</Callout>

## Configurable limits and defaults [#configurable-limits-and-defaults]

All values below are tunable via `CONNECTORSMQTT_CAPABILITIES_*` environment variables (see
[Configuration](/connectors/mqtt/concepts/configuration)).

| Capability                     | Default          | Min | Max   | Notes                                                                                                                                                                                                                                                                                                     |
| ------------------------------ | ---------------- | --- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MaximumPacketSize`            | `4194304` (4 MB) | 1   | —     | Maximum PUBLISH payload + header size in bytes. Clients sending larger packets are disconnected.                                                                                                                                                                                                          |
| `ReceiveMaximum`               | `1024`           | 1   | 65535 | Maximum concurrent in-flight QoS 1/2 publishes per client (flow control).                                                                                                                                                                                                                                 |
| `MaximumInflight`              | `8192`           | 1   | —     | Broker-wide in-flight QoS message cap.                                                                                                                                                                                                                                                                    |
| `MaximumSessionExpiryInterval` | `3600` s         | 0   | —     | Maximum value clients may request for `SessionExpiryInterval`.                                                                                                                                                                                                                                            |
| `MaximumMessageExpiryInterval` | `86400` s        | 0   | —     | Maximum allowed message expiry. **RPC publishes only**: if `MessageExpiryInterval` is set on a `commands/` or `queries/` PUBLISH and is shorter than `RpcTimeoutSeconds`, the effective RPC timeout becomes `min(RpcTimeoutSeconds, MessageExpiryInterval)`. Does not apply to queue or events publishes. |
| `MaximumQos`                   | `2`              | 0   | 2     | Highest QoS the broker grants.                                                                                                                                                                                                                                                                            |
| `MinimumProtocolVersion`       | `4` (MQTT 3.1.1) | 4   | 5     | MQTT 3.1 (level 3) is rejected at CONNECT.                                                                                                                                                                                                                                                                |
| `MaximumClients`               | `0` (unlimited)  | 0   | —     | `0` = unlimited.                                                                                                                                                                                                                                                                                          |

## Protocol version support [#protocol-version-support]

| Protocol   | Level byte | Accepted     | Notes                                                                                                                                                                                                                                                                                 |
| ---------- | ---------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| MQTT 5.0   | `0x05`     | Yes          | Full feature set: user properties, reason codes, shared subscriptions, RPC flow.                                                                                                                                                                                                      |
| MQTT 3.1.1 | `0x04`     | Yes          | No user properties, no RPC, no `$share` queue consume.                                                                                                                                                                                                                                |
| MQTT 3.1   | `0x03`     | **Rejected** | CONNECT is refused for an unsupported protocol level. Because a level-3 CONNECT uses the MQTT 3.x CONNACK format, the byte returned is the v3 return code `0x01` ("unacceptable protocol version") — not one of the MQTT 5.0 [reason codes](/connectors/mqtt/reference/reason-codes). |

`MinimumProtocolVersion=4` is the hardcoded floor. Set
`CONNECTORSMQTT_CAPABILITIES_MIN_PROTOCOL_VERSION=5` to allow MQTT 5.0 clients only.

## Session semantics [#session-semantics]

Sessions are **in-memory and node-local**:

| Property                                              | Behavior                                                                                                                                                                              |
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `clean_start=false` (v5) / `clean_session=0` (v3.1.1) | Session is preserved in the node's memory. A reconnect to the **same node** within `SessionExpiryInterval` restores subscriptions and queued QoS 1/2 messages without re-subscribing. |
| Reconnect to a **different node**                     | Session is lost (not replicated across nodes).                                                                                                                                        |
| `clean_start=true`                                    | Fresh session; no state carried over.                                                                                                                                                 |

Restored sessions do **not** replay historical Events-Store messages — the bridge
re-subscribes at start-new-only after reconnect. See the
[no-replay gotcha](#gotcha-2-events-store-has-no-historical-replay).

## Transport listeners [#transport-listeners]

| Listener    | Default port | URL scheme        | Notes                                                                                                                                                              |
| ----------- | ------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| TCP (plain) | `1883`       | `tcp://host:1883` | Always active when `Port` is set (default `1883`).                                                                                                                 |
| TLS         | `8883`       | `tls://host:8883` | Active **only** when `Security` config is present. TLS min 1.2; mTLS supported. If no TLS material is configured, the listener is silently skipped with a warning. |
| WebSocket   | `8083`       | `ws://host:8083/` | Active when `WsPort` is set. TLS WebSocket (`wss://`) when Security config present.                                                                                |

## User properties (MQTT 5.0 only) and KubeMQ tags [#user-properties-mqtt-50-only-and-kubemq-tags]

MQTT 5.0 user properties map bidirectionally to KubeMQ message tags for Events,
Events-Store, and Queues patterns. MQTT 3.1.1 has no user properties.

| Direction                         | Mapping                                                                              |
| --------------------------------- | ------------------------------------------------------------------------------------ |
| PUBLISH → KubeMQ                  | `Properties.User` entries copied 1:1 into KubeMQ `Tags` (duplicate keys: last-wins). |
| KubeMQ delivery → MQTT subscriber | KubeMQ `Tags` copied into `Properties.User` on the injected PUBLISH.                 |

Hardcoded caps:

| Cap                                                  | Value          | Violation result                                                          |
| ---------------------------------------------------- | -------------- | ------------------------------------------------------------------------- |
| Maximum user properties per message                  | **32**         | MQTT 5.0: PUBACK `0x97`; MQTT 3.1.1: silent drop + `publish.error` audit. |
| Maximum total bytes (sum of all key + value lengths) | **4096 bytes** | Same as above.                                                            |

## Limitations [#limitations]

These are the design constraints to plan around — each is a hard property of the connector,
not a configuration choice:

| Limitation                                | Detail                                                                                                                                                                                      |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **No retain**                             | `RetainAvailable=0` — retained PUBLISH is dropped; `Will-retain` CONNECT rejected with `0x9A`.                                                                                              |
| **No durable subscriptions**              | Sessions are node-local and in-memory; reconnecting to a different node loses the session.                                                                                                  |
| **Queues are publish-only over MQTT**     | `queues/<ch>` accepts produce; consuming requires `$share/<group>/queues/<ch>`, which is **MQTT 5.0 only** (3.1.1 has no shared subscriptions).                                             |
| **Commands / Queries are MQTT 5.0 only**  | RPC uses `ResponseTopic` + `CorrelationData`; a 3.1.1 publish to `commands/`/`queries/` is silently dropped. MQTT clients can only be RPC **requesters** — responders run on the gRPC side. |
| **Events-Store has no historical replay** | MQTT subscriptions always start new-only; messages stored before subscribe are never delivered.                                                                                             |
| **Ruby client is the v3.1.1 subset**      | The `mqtt` gem speaks MQTT 3.1.1 only — no RPC, no `$share` queue consume, no user properties.                                                                                              |

## Gotcha reference [#gotcha-reference]

### Gotcha 1: retain is silently dropped at runtime [#gotcha-1-retain-is-silently-dropped-at-runtime]

`RetainAvailable=0` is advertised at CONNECT. If a client sends a retained PUBLISH anyway:

* The retain flag is silently **stripped**.
* The connector then **drops the message** and audits `publish.error` with text
  `"retain not supported"`.
* The **PUBACK succeeds** (`0x00`). The sender has no indication the message was dropped.
* No retained copy is stored; late subscribers receive nothing.

The **only** case that yields a CONNACK error is `Will-retain=true` at CONNECT, which
returns CONNACK `0x9A` (retain-not-supported), enforced before the session is established.

### Gotcha 2: Events-Store has no historical replay [#gotcha-2-events-store-has-no-historical-replay]

Events-Store subscriptions over MQTT always start new-only. Unlike the REST/gRPC API
(which offers six replay positions), MQTT subscribers receive **only messages published
after the subscription is established**. Messages stored before a client subscribes are
never delivered.

### Gotcha 3 — `$share` group name is audit-only; all groups compete in one pool [#gotcha-3--share-group-name-is-audit-only-all-groups-compete-in-one-pool]

Standard MQTT brokers deliver a separate copy of each message to each `$share` group. The
KubeMQ connector does **not**. All `$share` subscribers on all groups compete in a **single
KubeMQ queue pool**: each message is consumed exactly once, regardless of group name. The
group name is recorded in audit and metrics only.

### Gotcha 4 — RPC requires MQTT 5.0 and PUBACK is immediate [#gotcha-4--rpc-requires-mqtt-50-and-puback-is-immediate]

Publishing to `commands/` or `queries/` from an MQTT 3.1.1 client is silently dropped
(PUBACK `0x00`, no RPC issued). The PUBACK for a valid MQTT 5.0 RPC publish is also sent
**immediately**, before the response arrives — clients must implement their own
response-wait timeout.

### Gotcha 5 — literal `.` in a topic segment conflates with `/` [#gotcha-5--literal--in-a-topic-segment-conflates-with-]

`events/a.b/c` and `events/a/b/c` both produce KubeMQ channel `a.b.c`. Avoid dots inside
path segments. See [Topic Grammar](/connectors/mqtt/reference/topic-grammar).

### Gotcha 6 — overlapping wildcard filters deliver multiple copies [#gotcha-6--overlapping-wildcard-filters-deliver-multiple-copies]

Each unique subscribe filter has its own independent bridge entry. A publish matching N
active wildcard filters results in N deliveries to the client. There is no cross-entry
deduplication.

## Related [#related]

<Cards>
  <Card title="Topic Grammar" href="/connectors/mqtt/reference/topic-grammar" description="Topic-to-channel mapping, wildcards, shared subscriptions, and RPC topics." />

  <Card title="Reason Codes" href="/connectors/mqtt/reference/reason-codes" description="Every MQTT 5.0 reason code the connector produces and what triggers it." />

  <Card title="Connections Endpoint" href="/connectors/mqtt/reference/connections-endpoint" description="The connections snapshot endpoint and the three Prometheus metrics." />

  <Card title="QoS & Sessions" href="/connectors/mqtt/concepts/qos-and-sessions" description="QoS levels, clean-start vs persistent sessions, and the retain/durability caveats in depth." />
</Cards>
