Topic mapping
How the KubeMQ MQTT connector maps topics to patterns and channels — the prefix grammar, slash-to-dot, wildcards, $share consume, and $reply RPC replies.
The KubeMQ MQTT connector maps every MQTT topic to a KubeMQ messaging pattern and channel through a
well-defined grammar. The first topic segment (the prefix) selects the KubeMQ pattern; the
remaining segments become the channel name with / replaced by .. Understanding this grammar
is essential before writing any producer or consumer code.
Prefix-to-pattern table
| MQTT topic | 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 = produce only | queues/jobs/email | jobs.email |
$share/<group>/queues/<ch> | Queues | subscribe = consume (QoS ≥ 1) | $share/g1/queues/jobs/email | jobs.email |
commands/<ch> | Commands (RPC) | publish = send (MQTT 5.0 only) | commands/svc/reboot | svc.reboot |
queries/<ch> | Queries (RPC) | publish = send (MQTT 5.0 only) | queries/svc/status | svc.status |
$reply/<clientID>/<suffix> | (broker-local) | subscribe + RPC ResponseTopic | $reply/c1/inbox | not routed to KubeMQ |
Separator conversion: / → .
MQTT uses / as the path separator; KubeMQ uses .. The connector converts every / in the
channel portion of the topic to .:
events/site1/sensors/temp
↓ strip the prefix
site1/sensors/temp
↓ replace / with .
site1.sensors.temp ← KubeMQ channelThis conversion is one-way on delivery: when the connector delivers a KubeMQ message to an MQTT
subscriber, the channel's . separators are not converted back. The MQTT subscribe filter must
match the dotted form.
A literal . in a topic segment is lossy. A . inside a segment maps to . in the channel —
indistinguishable from a /-converted .. So events/a/b/c, events/a.b/c, and
events/a/b.c all resolve to the same channel a.b.c. Use / exclusively for hierarchy in MQTT
topics; reserve . for the channel names used on gRPC/REST clients.
Prefixless topics and DefaultPattern
A topic with no recognized prefix (e.g. sensor/data) is routed to the configured
DefaultPattern:
DefaultPattern | Behaviour |
|---|---|
events (default) | Routed to Events on channel sensor.data |
store | Routed to Events-Store |
none | Publish rejected — PUBACK 0x90; subscribe rejected — SUBACK 0x8F |
Configure with CONNECTORSMQTT_DEFAULT_PATTERN (default events).
Wildcard subscriptions — Events only
MQTT wildcards are supported on Events subscriptions only. A wildcard subscribe on any other
pattern is rejected with SUBACK 0xA2 (wildcard-subscriptions-not-supported).
| MQTT wildcard | KubeMQ equivalent | Example filter | Matches |
|---|---|---|---|
+ (single level) | * | events/site1/+ | events/site1/temp, events/site1/hum |
# (multi level) | > | events/site1/# | events/site1/temp, events/site1/a/b/c |
Rules:
#must be the final segment of the topic filter.- Both wildcards may appear in one filter:
events/+/sensors/#. - A non-Events wildcard subscribe returns SUBACK
0xA2.
Overlapping wildcard filters deliver multiple copies. Each distinct Events subscribe filter
creates an independent bridge entry, and there is no cross-entry deduplication. If a publish
matches N of a client's overlapping filters (e.g. #, events/#, and the exact topic), the
client receives N copies. Use non-overlapping filters when duplicate delivery is unacceptable.
Queue consume: $share shared subscriptions
A plain queue subscribe (queues/<ch>) is not allowed — it returns SUBACK 0x83. Queue
consumption requires an MQTT 5.0 shared subscription:
$share/<group>/queues/<channel>| Component | Meaning |
|---|---|
$share | MQTT 5.0 shared-subscription prefix |
<group> | Group name — an audit/metrics label only (see the caveat below) |
queues/<channel> | Must resolve to the Queues pattern |
QoS must be ≥ 1 — a QoS 0 shared-queue subscribe returns SUBACK 0x83.
The $share group name is audit/metrics-only. All groups compete in one shared KubeMQ
queue pool — this is not MQTT per-group-copy semantics. $share/A/queues/x and
$share/B/queues/x consume from the same pool (one copy total, any consumer wins), not one
copy per group. For true fan-out to independent consumer groups, use different KubeMQ channels.
RPC reply topics: $reply/<clientID>/<suffix>
$reply is a broker-local reserved namespace for RPC response routing. It is never routed
to KubeMQ — it stays inside the broker.
| Rule | Details |
|---|---|
| Format | $reply/<clientID>/<suffix> — 3 segments minimum |
| Own namespace | A client may only subscribe to / use as ResponseTopic its own $reply/<own-clientID>/... |
| Foreign namespace | Using another client's $reply namespace → PUBACK 0x83 (publish with a foreign ResponseTopic) |
| Routing | Never forwarded to KubeMQ |
An RPC client subscribes to its own reply topic before publishing the request, then sets it as
Properties.ResponseTopic on the publish. See Commands
and Queries for the full flow.
MQTT 5.0 User Properties ↔ KubeMQ Tags
On MQTT 5.0 connections, User Properties on a PUBLISH are carried into the KubeMQ message
Tags, and vice versa on delivery. This mapping is 5.0 only — MQTT 3.1.1 has no User
Properties field.
- Inbound — every
Properties.Userentry on a 5.0 PUBLISH is copied 1:1 into the KubeMQ messageTags(duplicate keys are last-wins). Applies to Events, Events-Store, Queues publishes, and the RPC bridge. - Outbound — when a KubeMQ message is delivered to a 5.0 MQTT subscriber, its
Tagsare written back asProperties.User. A 3.1.1 subscriber receives no user properties.
Caps (per message):
| Cap | Limit | Exceeded on 5.0 | Exceeded on 3.1.1 |
|---|---|---|---|
| Max user-property count | 32 | PUBACK 0x97 + publish.error | Silent drop + publish.error |
| Max total bytes (all keys + values) | 4096 | PUBACK 0x97 + publish.error | Silent drop + publish.error |
When either cap is exceeded the message is not routed.
Reason codes for invalid topics
| Trigger | Packet | Code |
|---|---|---|
DefaultPattern=none, prefixless publish | PUBACK | 0x90 topic-name-invalid |
DefaultPattern=none, prefixless subscribe | SUBACK | 0x8F topic-filter-invalid |
| Empty channel segment | SUBACK | 0x8F topic-filter-invalid |
| Non-Events wildcard subscribe | SUBACK | 0xA2 wildcard-subscriptions-not-supported |
Plain queues/<ch> subscribe | SUBACK | 0x83 implementation-specific |
QoS 0 $share/*/queues/<ch> subscribe | SUBACK | 0x83 implementation-specific |
Foreign $reply namespace (publish) | PUBACK | 0x83 implementation-specific |
Related
Was this page helpful?
QoS and sessions
QoS 0/1/2 on the KubeMQ MQTT connector — the QoS each pattern requires, ack-on-PUBACK for Queues, node-local sessions, and why retain is silently dropped.
Getting Started
Connect a stock MQTT client to KubeMQ and run a publish-and-subscribe round-trip over the Events pattern in minutes — no KubeMQ SDK required.