If you have ever built a system on MQTT 3.1.1 and ended up encoding metadata into topic names or stuffing JSON envelopes inside payloads to carry information about the message, you have already felt the gap that user properties fill. MQTT 3.1.1 had no place for application-defined metadata in a message; the protocol’s headers were rigidly defined, and anything an application wanted to add had to go into the payload itself, where it tangled with the actual data the message was carrying.
MQTT 5 introduces user properties: arbitrary UTF-8 key-value pairs that can be attached to most MQTT control packets. They behave a lot like HTTP headers, and they unlock a flexibility that MQTT 3.1.1 simply could not offer. This article covers what user properties are, where they can appear, how they are encoded, the main use cases they enable, the limits and gotchas to be aware of, and how to design with them well. It is a technical reference; the MQTT 5 overview and each related feature have their own dedicated articles in this category.
Table of Contents
User properties at a glance
| Aspect | Detail |
|---|---|
| What | UTF-8 key, UTF-8 value pairs of application-defined metadata |
| Encoded as | UTF-8 String Pair, an MQTT 5 wire-level data type |
| Where they appear | CONNECT, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, DISCONNECT, AUTH, plus the will properties in a CONNECT |
| Where they do not appear | PINGREQ, PINGRESP (the two simplest packets) |
| How many | Multiple per packet, including duplicate keys |
| Maximum total size | Bounded by the broker’s Maximum Packet Size (advertised in CONNACK) |
| Interpretation by the broker | None — the broker forwards them unchanged to subscribers on PUBLISH |
| Interpretation by the client | Whatever the application defines |
Why user properties were added
To understand why user properties matter, look at what MQTT 3.1.1 developers were doing without them.
Metadata in topics. A common workaround was to put metadata into the topic structure. A device wanting to identify itself, say, ended up with topics like data/v2/firmware-1.4.3/site-A/device-7/temperature. The version number and the firmware revision and the site identifier are not really about routing; they are about describing the message, but the topic was the only place an application could put them where the broker could see them.
Metadata in payloads. Another workaround was to wrap the actual data in a JSON or Protocol Buffers envelope that carried both the data and a metadata block. Every consumer of the message had to know how to unpack the envelope to get at the data. Every change to the metadata structure was a coordinated update across publishers and subscribers. The protocol provided no hook for any of this.
No standard way to identify, trace, or version messages. Without protocol-level metadata, every system invented its own conventions for tagging messages with identifiers, correlation IDs, or version numbers. In a deployment spanning multiple teams, those conventions inevitably diverged, and translating between them became a backend chore.
User properties solve all three of these directly. The protocol now has a designated place for application-defined metadata, separate from both the topic (which is for routing) and the payload (which is for the actual data). The mechanism is generic, so the same field works for traceability, versioning, content description, routing hints, or anything else the application needs. And because user properties are part of the protocol, every MQTT 5 client and broker handles them in the same way.
What a user property is
A user property is a pair of UTF-8 strings: a key and a value. The key is the property’s name; the value is its content. Both are arbitrary, application-defined, and opaque to the protocol. MQTT itself imposes no schema on either; that is entirely up to the application.
For example, a PUBLISH carrying a sensor reading might also carry user properties like:
publisher-id = "device-7"
firmware = "1.4.3"
trace-id = "abc123def"
units = "celsius"
Each of these is a separate user property on the same PUBLISH. The broker forwards them unchanged to every subscriber that receives the message; the subscribers can read whichever they care about and ignore the rest.
Multiple user properties on the same packet are allowed, and there is no restriction against duplicate keys. A packet can carry two properties with the same key but different values, and the order in which they appear in the packet is preserved when the broker forwards them. This is occasionally useful for properties that genuinely have multiple values (think of an HTTP header that can be specified multiple times), though the more common pattern is unique keys.
On the wire, each user property is encoded as a UTF-8 String Pair, a data type that MQTT 5 introduced specifically to make user properties (and a few other key-value protocol fields) clean. The encoding is straightforward: a length-prefixed UTF-8 key followed by a length-prefixed UTF-8 value. Multiple user properties on the same packet are simply repeated. Client libraries handle the encoding and decoding; application code sees user properties as a list (or sometimes a multimap) of string pairs.
Where user properties can appear
Almost every MQTT 5 control packet can carry user properties:
- CONNECT — properties from the client at connection time.
- CONNACK — properties from the broker in response.
- PUBLISH — properties that travel from publisher to subscribers as part of a message.
- PUBACK, PUBREC, PUBREL, PUBCOMP — properties on the QoS 1 and 2 acknowledgement packets.
- SUBSCRIBE, SUBACK — properties on subscriptions and their acknowledgements.
- UNSUBSCRIBE, UNSUBACK — properties on unsubscribes and their acknowledgements.
- DISCONNECT — properties on disconnect packets in either direction.
- AUTH — properties on enhanced authentication exchanges.
- Will properties (inside CONNECT) — properties attached to the will message that the broker will publish on ungraceful disconnect.
The only packets that do not support user properties are PINGREQ and PINGRESP, which are the two-byte heartbeats whose entire purpose is to be minimal. Everything else can carry application-defined metadata.
The most commonly useful placement is on PUBLISH, because that is where application-level information about a message naturally belongs and where the broker forwards properties to subscribers unchanged. Properties on CONNECT and CONNACK are useful for application-level handshaking between client and broker (above and beyond what the protocol’s own properties cover). Properties on the QoS acknowledgement packets are less common but available when needed, for example to carry application-level acknowledgement information that piggybacks on the protocol-level acknowledgement.
What the broker does with user properties
For the most common case — properties on PUBLISH — the broker’s behavior is simple and consistent: it forwards them unchanged to every subscriber that receives the message. The properties are part of the message’s metadata, not something the broker interprets or modifies. The same user properties that the publisher sent are what each subscriber gets, in the same order, with the same keys and values.
This is what makes user properties useful as a transport for application metadata. The broker does not need to know what your trace-id or units or priority property means; it just carries it through. Subscribers that understand the property can act on it; subscribers that do not understand it can ignore it. Each subscriber chooses its own behavior based on which properties it knows about.
A few details worth knowing:
- Brokers do not add, remove, or rewrite user properties on forwarded PUBLISH packets. What goes in is what comes out. (Some bridge or gateway components in front of the broker may modify them, but plain MQTT brokers should not.)
- Properties on acknowledgement packets are between the client and the broker, not subscribers. A user property on a PUBACK does not reach any subscriber; it is part of the publish-acknowledgement conversation between the publisher and the broker.
- Properties on the CONNECT do not reach subscribers either. They are part of the connection-establishment conversation between the connecting client and the broker.
- Will properties are forwarded as part of the will PUBLISH. When the broker publishes a will, any user properties the client attached to the will (as will properties in CONNECT) become user properties on the published PUBLISH, reaching subscribers as a normal PUBLISH would.
In short: properties on PUBLISH are end-to-end, publisher to subscriber. Properties on other packets are point-to-point, between the client and the broker for that particular exchange.
What user properties are used for
The protocol does not prescribe what user properties should contain, but a few patterns recur in real deployments. Each addresses a real need that MQTT 3.1.1 left to the application.
Payload context
Telling subscribers something about how to interpret the payload, without baking it into the topic or the payload itself. Examples include the unit a numeric value is in (units = "celsius"), the schema version that produced the payload (schema-version = "2.1"), the firmware version of the publisher (firmware = "1.4.3"), or other context-of-creation information.
This pattern is especially useful when a topic carries data of the same kind from devices that may evolve their payload format independently. A subscriber receiving a temperature reading no longer needs to assume “this is always Celsius”; the publisher can say so explicitly, and a newer subscriber can use that information to handle the case where different publishers use different units. MQTT 5’s payload format indicator and content type properties cover specific cases of this (binary vs. UTF-8, MIME type), but user properties handle the open-ended cases where the application’s specific context cannot be expressed by a standardized property.
Routing and processing hints at the application layer
While topics are for protocol-level routing through the broker, user properties can carry hints used by application-level routing logic that runs after the message arrives. An ingestion system that subscribes to a broad topic and then dispatches messages to different downstream systems can use a user property like destination = "warm-storage" or priority = "high" to make that decision quickly, without parsing the payload.
This is particularly useful when MQTT is the transport between heterogeneous teams or systems, and the dispatch logic is more nuanced than what topic-based filtering alone supports. The broker still does its normal subject-based filtering on topics; user properties layer additional, application-defined criteria on top.
Traceability across systems
In any non-trivial distributed system, knowing where a message came from and being able to follow it through multiple stages is essential for debugging and observability. User properties give MQTT a standard place to put traceability metadata, comparable to how distributed tracing systems use HTTP headers like traceparent.
A publisher can attach a user property like trace-id = "abc123" (and optionally span-id, parent-id, and others, following whichever tracing convention is in use) to every PUBLISH. The broker forwards them to every subscriber. A subscriber that re-publishes derived messages can include the same trace ID on its publishes. The result is that a single trace ID, attached at the source, follows the message through every subsequent hop, giving operators a way to reconstruct the full path of a piece of data through the system.
This is one of the highest-value patterns in MQTT 5 for any deployment that spans multiple processes or teams.
Application-level identity
Closely related: identifying which client published a message, beyond what the protocol already exposes. The broker knows which client (by ClientId) sent the PUBLISH, but it does not forward that information to subscribers. A user property like publisher = "device-7" puts that information on the message itself, where subscribers can use it.
Without this, a subscriber receiving a message has no built-in way to know who sent it, only the topic the message arrived on. Topic structure can carry the publisher identity, but doing so forces it into the routing tree where it does not really belong. User properties keep the topic clean and put the identity where it belongs: in the message metadata.
Multi-tenancy and partitioning
In a multi-tenant deployment, every message often needs to carry the tenant identifier alongside its data. Topics can be structured to make this explicit (tenant/<id>/...), but doing so leaks tenant identity into the routing tree, complicates wildcard subscriptions, and makes it awkward to support a message that is logically about multiple tenants. A user property like tenant = "acme-corp" keeps the topic structure tenant-agnostic and tags each message with its tenant context.
The same pattern applies to other partitioning dimensions: customer ID, region, department, environment (dev/staging/prod), or any other label that is interesting to consumers but not strictly part of routing.
Encoding and on-the-wire format
A user property is encoded as a UTF-8 String Pair: the key is a length-prefixed UTF-8 string, followed by the value as a length-prefixed UTF-8 string. Length prefixes are two-byte unsigned integers, so each individual string is limited to 65,535 bytes in encoded form (the same limit that applies to topics and to other UTF-8 strings in MQTT).
Multiple user properties on the same packet appear sequentially within the properties section of the packet. There is no explicit count; the parser reads pairs until the end of the properties section is reached. This is why duplicate keys are allowed: the parser does not deduplicate them, and the order is preserved.
The total size of all user properties on a single packet is bounded by the packet’s overall size limit. MQTT 5 lets the broker advertise a Maximum Packet Size in the CONNACK, and a packet that would exceed it will be rejected with a 0x95 (Packet Too Large) reason code. In practice, generous packet size limits (megabytes) mean user properties are rarely the thing that bumps into this limit, but a deployment that uses many properties or very long values should be aware that the limit exists.
User property values can be empty strings. A property with a key but no value is valid and is sometimes used as a tag or flag (the presence of the property carries meaning; the value is irrelevant).
A worked example: traceability through a multi-stage pipeline
To make the end-to-end story concrete, trace user properties through a realistic flow.
A field device publishes a temperature reading. Its PUBLISH carries:
Topic: sensors/site-a/device-7/temperature
Payload: 22.4
User properties:
publisher = "device-7"
firmware = "1.4.3"
units = "celsius"
trace-id = "f3a8c1d2e7b4"
The broker receives the PUBLISH. It routes the message by topic, exactly as it would in MQTT 3.1.1; user properties play no role in the broker’s routing decision. The broker forwards the message to every subscriber whose topic filter matches, with all four user properties intact.
Three subscribers receive the message, each interested in different properties:
- A live dashboard subscribed to
sensors/site-a/+/temperaturereadsunitsto format the value correctly on screen. It ignores the other properties. - An archival service subscribed to
sensors/#readspublisherandfirmwareto tag the stored record with provenance information, in case the source’s behavior needs to be investigated later. It also storestrace-idfor cross-system correlation. - An alerting service subscribed to
sensors/+/+/temperaturechecks the value against thresholds. If it triggers an alarm, it publishes a new message toalerts/temperatureand copiestrace-idonto the new PUBLISH. The threshold-check logic does not need any of the other properties, but propagatingtrace-idis the cheap way to make the eventual alert traceable back to the original reading.
When operations later wants to know which sensor reading caused a particular alert, they query the alerting log for the alert’s trace-id, find the matching original PUBLISH in the archival store, and have the full provenance: the device, its firmware version, and the units the value was reported in. None of this required the broker to do anything special; user properties carried the context through every hop, and each subscriber used whichever subset it needed.
This pattern — application-defined identity and traceability propagating through pub/sub — is one of the things that simply was not practical in MQTT 3.1.1 without embedding identifiers in topics or payloads. User properties make it idiomatic.
Limits and considerations
A few practical considerations for using user properties well.
Wire overhead. Every user property adds bytes to every packet that carries it. On a high-volume system sending small messages, a handful of long property keys and values can dwarf the payload itself. Keep keys short (single words rather than sentences), keep values concise, and remember that user properties travel on every PUBLISH, every time. The MQTT 5 Topic Alias mechanism exists precisely to mitigate this for repeated topic names; there is no equivalent for user properties.
No standardized vocabulary. User properties are application-defined, which means the broker enforces no schema. Two teams publishing to the same MQTT system can independently invent the same property key for different purposes. In multi-team deployments, document and version your user property vocabulary the way you would document any other interface.
No protocol-level type system. Values are UTF-8 strings. Application code that needs typed data (numbers, booleans, structured values) has to parse or format strings, and there is no protocol-level enforcement of those formats. If you put priority = "high" on one publish and priority = "1" on another, the protocol is fine with both; your code is the only thing that knows the difference matters.
Broker compatibility. Some brokers, especially older or hosted ones, may impose limits on user property count, key length, or total size beyond what the spec requires. Test with the broker you are actually deploying to. The broker’s Maximum Packet Size advertisement gives you the outer bound; individual brokers may enforce tighter limits without explicitly advertising them.
Privacy and security. User properties travel in the clear over plain MQTT, and even over TLS they are visible to anyone with broker access. Do not put secrets, credentials, or personally identifying information in user properties unless you understand who can read them. The broker logs and the broker’s operators can typically see properties on every message that flows through.
Topic vs. property: pick once. A common indecision is whether to put something in the topic structure or in a user property. The rule of thumb: if subscribers will routinely filter on it (subscribe to one value of it, ignore others), put it in the topic so the broker can filter. If consumers will mostly receive it and act on it after the fact, put it in a user property. The choice matters because the broker can do topic-based filtering efficiently and cheaply; it does not filter on user properties.
How user properties connect to the rest of MQTT 5
User properties are the most flexible single addition in MQTT 5, and they touch most other features:
- Will messages can carry user properties via the CONNECT’s will properties; they become properties on the published will if it fires.
- The Request/Response Pattern uses Correlation Data and Response Topic, which are protocol-defined properties, but applications often supplement these with user properties for additional context.
- Payload Format Description complements user properties: format indicator and content type are standardized properties, where open-ended descriptive metadata uses user properties.
- Improved client feedback can carry user properties on acknowledgement packets and DISCONNECTs, alongside the reason codes and reason strings covered in that article.
Used well, user properties bring MQTT in line with the kind of message-level metadata that modern messaging and HTTP-based systems take for granted, without compromising MQTT’s small footprint.
Frequently asked questions
What are user properties in MQTT 5?
UTF-8 key-value pairs that an application can attach to most MQTT control packets to carry arbitrary metadata. They behave like HTTP headers. The protocol does not interpret them; on PUBLISH packets, the broker forwards them unchanged to subscribers.
Where can user properties appear?
On almost every MQTT 5 control packet: CONNECT, CONNACK, PUBLISH, the QoS 1 and 2 acknowledgements (PUBACK, PUBREC, PUBREL, PUBCOMP), SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, DISCONNECT, AUTH, and as will properties inside CONNECT. The only exceptions are PINGREQ and PINGRESP.
Can a packet have multiple user properties?
Yes. Multiple user properties on the same packet are explicitly allowed, including duplicate keys with different values. The order is preserved when the broker forwards them.
What does the broker do with user properties?
For PUBLISH, the broker forwards user properties unchanged to every subscriber. For other packets, the properties are part of the conversation between the client and the broker for that particular exchange and do not propagate further.
What are user properties used for?
Common patterns include payload context (units, schema version, firmware version), application-level routing and processing hints, traceability metadata (trace IDs, correlation context), publisher identity at the application layer, and tenant or partition labels.
Do user properties exist in MQTT 3.1.1?
No. MQTT 3.1.1 has no equivalent. Applications running on MQTT 3.1.1 had to encode metadata into topics or payloads. User properties are an MQTT 5 addition.
Is there a size limit on user properties?
Each individual key or value is limited to 65,535 bytes by MQTT’s UTF-8 string encoding. The total size of all user properties on a single packet is bounded by the broker’s Maximum Packet Size, which is advertised in the CONNACK. In practice the per-packet limit is generous.
Should I put information in the topic or in a user property?
If subscribers will filter on it (subscribe to one value, ignore others), put it in the topic where the broker can filter efficiently. If consumers mostly receive it and act on it after the fact, put it in a user property. Topics are for routing; user properties are for descriptive metadata.
