MQTT Topics and Wildcards
MQTT's topic hierarchy is what makes the protocol elegant for IoT. Publishers don't know who's listening; subscribers don't know who's publishing; the broker matches the two based on topic patterns. The catch is that the topic structure is your schema — and once devices are deployed using it, changing it is hard. A few hours of design up front prevents years of friction.
Topic structure basics
A topic is a string of levels separated by forward slashes:
building1/floor2/room204/temperature
factory/north/lineA/conveyor3/status
home/livingroom/light/state
Rules:
- UTF-8, case-sensitive.
- Forward slash is the level separator.
- No leading or trailing slashes (best practice).
- Empty levels are allowed but confusing — avoid them.
- Topics starting with $ are reserved (often used by brokers for system topics like $SYS/broker/uptime).
The two wildcards
| Wildcard | Matches | Position |
|---|---|---|
| + | Exactly one level | Any position |
| # | Zero or more levels | Must be the last character of the filter |
Wildcard examples
Subscription: building1/floor2/+/temperature
Matches: building1/floor2/room201/temperature
building1/floor2/room202/temperature
building1/floor2/lobby/temperature
Does NOT: building1/floor2/room201/door/temperature (too many levels)
building1/floor3/room201/temperature (different floor)
Subscription: building1/#
Matches: building1/floor1
building1/floor1/room101
building1/floor1/room101/temperature
building1/floor2/lobby/light/state
(literally everything starting with building1/)
Subscription: +/floor2/+/temperature
Matches: building1/floor2/room201/temperature
building2/floor2/lobby/temperature
(any building, floor2, any room, temperature)
Designing topic hierarchies
The conventional structure goes from general to specific, left to right:
<domain>/<site>/<area>/<device>/<measurement>
<tenant>/<category>/<device-id>/<event>
This structure lets wildcards do the work:
- "All temperatures in building 1":
building1/+/+/temperature(orbuilding1/#filtered downstream). - "All sensors on floor 2":
+/floor2/#. - "All readings from one device":
+/+/+/dev_abc123/+.
If you put the device ID at the front, you've made cross-device queries hard. If you put the measurement type at the back, you've made "all readings from this device" easy. Order reflects the dominant query pattern.
Consistency conventions
Pick rules and apply them everywhere:
- Casing. All lowercase, or all camelCase — pick one.
- Plurals. Singular (temperature, not temperatures).
- Identifiers. UUIDs or readable names? Pick one.
- Separator within a level. Hyphen, underscore, or camelCase? Pick one.
- Direction. Use sub-paths to indicate command vs telemetry:
device/+/statefor status from device,device/+/cmdfor commands to device.
Access control via topic prefixes
Broker ACLs typically grant access on topic patterns. Designing the hierarchy with multi-tenant ACLs in mind:
Tenant A: tenants/tenantA/# (publish + subscribe)
Tenant B: tenants/tenantB/# (publish + subscribe)
Admin: # (everything)
Putting tenant at the front of the topic makes ACL configuration trivial. Putting it deeper makes per-tenant isolation hard.
Topic naming antipatterns
- Putting JSON in topic names. The topic is metadata; the payload is data. Don't split structured data across both.
- Per-message topics. A new topic for every message ("message/12345") explodes broker memory.
- Embedding session IDs. Topics persist; sessions don't. Use payload fields instead.
- Different shapes per device. If some devices publish to
temp/d1and others tod2/temp, no wildcard works for both. - Spaces, special characters. Topics technically allow most UTF-8 but life is easier without quoting concerns.
System topics
Topics starting with $ are reserved for the broker. Common ones:
$SYS/broker/uptime— broker uptime.$SYS/broker/clients/connected— number of connected clients.$SYS/broker/messages/received— total received.
Don't publish to $-prefixed topics yourself. Subscribe to read broker telemetry.
Shared subscriptions (MQTT 5)
MQTT 5 added shared subscriptions: multiple subscribers split incoming messages between them rather than each receiving every message. Syntax:
$share/<group>/<topic-filter>
Example: $share/workers/factory/+/sensor/+
Used to scale consumers horizontally. Without it, every consumer gets every message and they need to coordinate. With it, the broker load-balances.
Retained messages and topic design
A retained message stays on its topic until replaced. New subscribers get the most recent retained value immediately. Topic design implications: use retained for "current state" topics (last reading, current status) but not for "events" (this happened) where receiving stale data on subscribe would be misleading. See MQTT retained messages.
Frequently Asked Questions
What is an MQTT topic?
A UTF-8 string organized as a hierarchical path, separated by forward slashes — for example, "building1/floor2/room204/temperature". Publishers send messages to specific topics; subscribers receive messages by subscribing to topic patterns. Topics are created implicitly on first use; there's no schema or pre-registration.
What are MQTT wildcards?
Two wildcard characters used in subscriptions but not publishes. The plus sign (+) matches exactly one level: "building1/+/temperature" matches building1/floor1/temperature, building1/floor2/temperature, etc. The hash (#) matches zero or more levels and must be the last character: "building1/#" matches everything under building1.
How should I structure topic hierarchies?
From general to specific, left to right. Common patterns: domain/site/area/device/measurement (e.g., factory/north/lineA/conveyor3/speed) or tenant/category/device/event (e.g., tenant42/sensor/dev_abc123/reading). Consistency matters more than the specific shape — pick a structure and apply it everywhere.
Can I use wildcards in publish messages?
No. Publishes go to specific, fully-qualified topic names. Wildcards are subscription-only. Trying to publish to a topic containing + or # produces undefined behavior (typically broker rejects with a protocol error).
How do brokers enforce access control on topics?
Through ACL rules tied to client identity — typically a username, certificate, or token. Rules grant publish, subscribe, or both on specific topic patterns. Most brokers support wildcards in ACL patterns, so "tenant42/#" grants access to everything under that tenant's prefix. Designing the topic hierarchy with ACLs in mind is essential — it determines what isolation between users or services looks like.
Related Guides
More From This Section
All IoT Protocols Guides
MQTT, CoAP, Zigbee, Thread, Z-Wave, Matter, Modbus, and OPC UA.
Bluetooth Low Energy for IoT
How BLE works for IoT — advertising vs connections, GATT profile, pairing, BLE 5 features, BLE mesh for multi-device…
CoAP Protocol Deep Dive
How CoAP works — request/response over UDP, confirmable vs non-confirmable messages, observe, block-wise transfer, DTLS…
Run a Speed Test
Measure download, upload, ping, and jitter in your browser.