MQTT 3.1.1 vs MQTT 5.0: Settings, Differences, and Tests
Explain every Mqttable New Client setting, then use publish, subscribe, and isolated wire tests to understand the problems MQTT 5 properties solve.

Switch a client from MQTT 3.1.1 to 5.0 on the same Broker and port, and it may not connect any faster. What changes is how precisely it can express its needs: how long a disconnected session should survive, when a message becomes stale, how many reliable messages it can receive without acknowledging them, and whether a brief connection interruption should immediately notify other devices.
In this guide, V3 means MQTT 3.1.1 and V5 means MQTT 5.0. Mqttable also offers 3.1 for systems explicitly requiring the older protocol. The client, Broker, and listener policy must support the chosen version. TCP, TLS, WebSocket, and port numbers do not determine that version.
Scroll the table sideways to see all columns.
| Question | MQTT 3.1.1 | MQTT 5.0 | Why the change helps |
|---|---|---|---|
| Start fresh now, but retain a session after disconnect? | One Clean Session flag combines both decisions | Clean Start and Session Expiry are separate | A fresh session can still have a defined recovery window |
| Are queued commands still useful when a device returns? | No protocol Message Expiry property | Message Expiry Interval | Prevents stale commands being delivered after recovery |
| Should a brief interruption trigger a Will immediately? | No Will Delay property | Will Delay Interval | Gives the same session time to recover before notification |
| How can a small receiver advertise its limits? | Local windows and Broker policies | Receive Maximum and Maximum Packet Size | Communicates outstanding-message and packet-size budgets |
| Why repeat a long Topic in every publication? | Every PUBLISH carries its Topic name | Topic Alias | A connection-local integer can replace a repeated Topic |
| Why did an operation fail? | Limited feedback such as CONNACK return codes and SUBACK | More reason codes, optional Reason String, server DISCONNECT | Makes failure location and meaning less ambiguous |
| How is a response matched to a request? | Application-specific Topic and payload conventions | Response Topic and Correlation Data | Carries routing and correlation outside the business payload |
| How are self-echo and retained replay controlled? | No equivalent standard subscription options | No Local, RAP, RH, Subscription Identifier | Supports bridges, replay control, and subscription attribution |
| Can authentication use several exchanges? | Username/password and transport mechanisms | Authentication Method/Data and AUTH | Supports challenge-response and in-connection reauthentication |
These additions do not replace publish/subscribe. Topic, QoS, Retain, username/password, and basic Wills already exist in 3.1.1. MQTT 5 Appendix C summarizes new features and some intended uses. The device, bridge, and command examples here are engineering interpretations, not a history of standards-committee decisions.
Choose a Broker in Connections, then open New Client / Add client. The Broker row identifies the endpoint this client belongs to. Host, Port, transport, TLS, and certificates are Broker settings, not new MQTT 5 properties. The laboratory endpoints below bind only to loopback; use your organization's endpoint and trusted credentials for real deployments.

- Keep the same ID; 2. V3.1.1 selected; 3. Keep Alive seconds; 4. Clean Session in V3.
- Keep the same ID
- V3.1.1 selected
- Keep Alive seconds
- Clean Session in V3

Name stays inside the app, Client ID identifies the session, credentials do not encrypt transport, and the version is independent of the port.
- Name stays in app
- Stable session ID
- Credentials, not TLS
- Version, not port
- Match listener policy
Scroll the table sideways to see all columns.
| Setting | Meaning and usage | Version relationship |
|---|---|---|
| Name | A Mqttable display name, limited to 255 UTF-8 bytes. A name such as Temperature Reader is not transmitted as the MQTT Client ID | Tool feature, unchanged between versions |
| Generate a new name | Generates a display name; it does not create a Broker account or change a connected device's identity | Tool feature |
| Client ID | The identity sent in CONNECT. The current form accepts bounded UTF-8 strings, subject to the Broker's own length and character policy | Shared protocol feature; a tool input limit is not universal Broker support |
| Generate Client ID | Creates a new test identity to reduce collisions. Do not regenerate it when you need an existing session | Tool feature |
Two connections using the same Client ID on the same Broker can cause the newer connection to take over the older one. Session recovery needs a stable Client ID. Disabling Clean Start while generating a different ID each time cannot recover the old session. MQTT 5 can also return a server-assigned identity; the generation button does not imply that it uses that mechanism.
Scroll the table sideways to see all columns.
| Option | Purpose | Requirements and limits |
|---|---|---|
| 5.0 | Uses MQTT 5 properties, reason codes, and subscription options | The listener must accept 5.0. There is no separate universal V5 port |
| 3.1.1 | Interoperates with many existing devices and libraries | CONNECT Protocol Level is 4, not the UI version string |
| 3.1 | Supports systems explicitly requiring the older protocol | Protocol Level is 3; this guide is not a second tutorial for that version |
| None | Sends no password | The Broker can still authenticate through username, certificates, network identity, or another policy. It does not force anonymous access |
| Password | Sends the credentials required by the Broker | Already supported in 3.1.1; a password does not encrypt plain TCP |
| JWT | Uses a token in the Password field | The Broker validates it. It normally travels as ordinary CONNECT Password, not a V5-only mechanism |
| SCRAM-SHA-1/256/512 | Performs MQTT 5 challenge-response authentication using AUTH exchanges | Both endpoints must support the same method. SHA-256 is tested here; the other methods are explained, not claimed as tested |
Mqttable currently exposes this selector under 5.0. Under 3.x it is hidden, while Username and Password remain available. At protocol level, a Broker supporting JWT can accept it in a 3.1.1 Password field. The location of JWT Tools in the V5 form does not make JWT a V5 feature.
The V5 addition is enhanced authentication, including a method, authentication data, and AUTH packets. Challenge-response need not transmit the original secret as CONNECT Password, and the protocol permits reauthentication within an existing connection. SCRAM does not replace TLS, and protocol support does not prove Mqttable has a button for initiating reauthentication. See the authentication guide and EMQX SCRAM configuration.

Password and JWT are not V5-only; the SCRAM method must match at both endpoints.
- Match listener policy
- No password sent
- Ordinary credentials
- Token in Password
- V5 AUTH exchange
Username and Password start empty. Enter the credentials required by the policy when using Password or SCRAM. None sends no password, even if an old saved value exists. The Password field is bounded by MQTT's two-byte length, at most 65,535 bytes; this is not a suggested password length and does not override provider restrictions.
- Raw password directly enters the credential. Show/hide only changes visibility; it does not change authentication, encryption, or permissions.
- Saved SecretRef selects a stored MQTT password in Credentials. The reference is not the password sent to the Broker and is not a V5 property; the Runtime resolves it when connecting. Repair a missing reference rather than sending its text as a password.
- Key/Value and Add/Remove belong to CONNECT User Properties, discussed below. They are not extra password fields.
Only synthetic laboratory credentials are used here. Screenshots do not expose passwords, signing keys, or usable token text. Never place production credentials in User Properties, Topics, payloads, screenshots, or an article.

The Runtime resolves the reference; it is not an MQTT property or a password string transmitted to the Broker.
- Direct credential entry
- Reuse a saved password
- Own laboratory reference
- Policy stays separate
JWT Tools is a Mqttable utility. None of these controls is an MQTT packet field.
Scroll the table sideways to see all columns.
| Tool setting | Meaning and usage |
|---|---|
| Algorithm | HS256 and RS256 are currently offered. Match the Broker's verification policy; successful generation does not prove the Broker accepts the token |
| Secret | The shared signing secret for HS256; both sides must agree. It is not an automatically generated MQTT password |
| Private Key (PEM) | RS256 signs with a PEM private key; the Broker normally holds the corresponding public key. Do not publish the private key |
| Claims Key/Value | Defines token claims. Add/Remove changes this token, not the Broker's validation policy |
| iat | Issued-at time. The tool's hint uses the current time; Unix timestamp units are seconds |
| exp | Expiry time. The current tool's default example is now plus 3,600 seconds, unrelated to MQTT session or message expiry |
| Encode | Opens the generation view for algorithm, key, and claims |
| Generate & Fill | Generates a token and fills Password. It does not prove authentication or publish permission |
| Preview | Parses Header, Payload, and time information from Password; it does not verify the signature |
| Open in JWT Debugger | Opens the separate debugger. Use its verification result, not successful Preview parsing, when checking a signature |
Whether Username, Client ID, subject, or another claim must match is a Broker policy. MQTT does not require them to be the same string.

The synthetic token is generated and masked; Broker acceptance is not implied.
- Signing algorithm
- HS256 signing secret
- Application claims
- Token expiry only
- Fill, not connect

Changing algorithm does not generate a key or verify the existing token.
- Match RS256 public key
- PEM signing private key
- Preview does not verify

- Fresh or resumed?; 2. Retention after loss; 3. Liveness interval; 4. Off sends zero; 5. Optional response info.
- Fresh or resumed?
- Retention after loss
- Liveness interval
- Off sends zero
- Optional response info
With MQTT 3.1.1 Clean Session=1, an old session is discarded and the new session is not retained after disconnect. With 0, the Broker attempts recovery and retains state afterward. State includes subscriptions and incomplete QoS 1/2 delivery. Retained messages are not part of an individual client's session.
In MQTT 5, Clean Start only decides whether to discard an old session at connection time. Session Expiry Interval controls retention after disconnect. The current New Client defaults to the cleanup flag enabled.
Scroll the table sideways to see all columns.
| MQTT 5 combination | At connection time | After disconnect |
|---|---|---|
| Clean Start on, Expiry 0 | Start a fresh session | End the session, similar to V3 Clean Session on |
| Clean Start on, Expiry 60 | Discard old state and create a new session | Retain the new session for 60 seconds |
| Clean Start off, Expiry 60 | Resume a session if one exists, otherwise create one | Retain it for 60 seconds |
| Clean Start off, Expiry 0 | Can still request an existing session | End the session when this connection closes |
Why separate the controls? The V3 flag combines "where should this connection start?" and "how long should later state survive?" It cannot express "start from scratch now, but retain this new session for one minute." V5 permits a recovery window without indefinitely retaining sessions for devices that never return.
Units are seconds, with a protocol range of 0 to 4,294,967,295. Omission defaults to 0. Zero ends the session after disconnect; the maximum means no time-based expiry at protocol level, still subject to Broker resource and administrative policies. The current New Client defaults to 0 and omits the property.
For offline QoS 1/2 recovery, use a stable Client ID, Clean Start off, and a deliberate positive interval. The experiment uses a two-second interval and checks CONNACK Session Present after a longer observation window. A restored UI subscription list is insufficient: Mqttable can restore configured subscriptions automatically. Check Session Present and queued messages to distinguish Broker recovery from local resubscription.
Units are seconds, range 0 to 65,535, with a current product default of 300. Zero disables MQTT Keep Alive. When there are no other MQTT control packets to send, PINGREQ/PINGRESP checks connection liveness; the Broker handles timeout under the protocol. It does not require a business message every interval, and is not a subscription or message lifetime.
Keep Alive exists in both versions. V5 adds Server Keep Alive, allowing CONNACK to state the value the client should use. Shorter intervals generally detect disconnection sooner but add traffic and device wakeups. Choose based on power, connectivity, and Broker policy rather than a universal best number.
The wire value is 0 or 1, with a specification default of 1 when omitted. In the locally fixed Mqttable, the default unchecked control explicitly sends 0; checked sends 1. An absent or nil field remains omitted.
One allows Reason String and User Properties in packets where permitted, but does not require the Broker to provide them. Zero restricts some packets' additional information. It does not disable reason codes or prohibit information permitted in PUBLISH, CONNACK, or DISCONNECT. Reason String is not a stable machine-readable interface.
V5 makes diagnosis more useful while letting small clients express a budget for extra strings and metadata. This control is not a sensitive-data filter.
The value is 0 or 1, defaulting to zero when absent. The current default is off, which omits the property. Enabling it asks for Response Information in CONNACK, but the Broker may still omit it.
It can help a requester construct response Topics alongside the PUBLISH Response Topic and Correlation Data properties. It does not subscribe to a response Topic, turn every publish into a request, or make the Broker execute a response. V3 applications must arrange these conventions outside those standard fields.

- QoS 1/2 window; 2. Inbound alias budget; 3. Whole-packet bytes.
- QoS 1/2 window
- Inbound alias budget
- Whole-packet bytes
The range is 1 to 65,535; zero is invalid. Omission defaults to 65,535. The initial Mqttable field is empty: its 65535 placeholder does not mean the property is already being sent.
In CONNECT, the client advertises the maximum outstanding QoS 1/2 PUBLISH messages it accepts from the Broker. The CONNACK value limits the opposite direction. It does not limit QoS 0 or specify messages per second.
V3 implementations can configure local in-flight limits and Broker policies, but cannot advertise this standard field to each other. V5 lets the sender pause new reliable messages at the receiver's limit. The auxiliary test receiver deliberately withholds PUBACK: with a window of two it does not receive all four messages before acknowledging, and one acknowledgement releases another message.
The property is a positive four-byte integer; zero is invalid. Omission adds no receiver size restriction beyond protocol encoding, implementation, and resource limits. Mqttable starts with an empty field; entering 0 means omit the property, not send an illegal zero.
CONNECT states the client's receiving limit, including Topic, Packet Identifier, properties, and payload. CONNACK states the Broker's receiving limit. A 100-byte payload is not necessarily a 100-byte PUBLISH.
This gives small devices a defined memory budget before an oversized message is transmitted. The Broker must not forward a packet larger than the client's limit. A sender's PUBACK does not prove a constrained subscriber received it. In the test, a 128-byte limit prevented forwarding a 512-byte payload; successful small messages before and after were the controls.
The range is 0 to 65,535, default zero if absent. The initial field is empty; zero permits no aliases. CONNECT advertises accepted Broker-to-client aliases. A publishing client's client-to-Broker allowance comes from CONNACK.
Topic Alias is a separate PUBLISH property, starting at 1 and never exceeding the peer's limit. A real Topic first establishes the mapping; subsequent packets on that connection can omit the repeated Topic name. Mappings do not survive reconnection and are not session state. Setting Topic Alias Max to ten does not automatically create ten mappings.
The V5 feature reduces repeated long-Topic overhead. Independent limits prevent saved bandwidth turning into an unbounded mapping-memory cost. The experiment checks both directions rather than treating one UI number as sufficient evidence.
User Properties are repeatable UTF-8 Key/Value pairs. Each uses a two-byte length field; repeated keys are permitted by the protocol. The current Client form supports 100 pairs, while the ordinary connection implementation requires non-empty Key and Value. This count is a product limit, not an MQTT limit.
Add/Remove edits this CONNECT's metadata, such as device-class=sensor or firmware=lab. The application or Broker implementation defines their meaning. CONNECT properties are not automatically forwarded to subscribers or copied onto future PUBLISH packets. Set message metadata separately in the publishing panel.
V5 supplies a standard container for extension metadata without placing everything in a Topic or business payload. It does not define every key or make untrusted metadata an authenticated authorization claim.

CONNECT metadata is separate from PUBLISH metadata; the current form permits 100 pairs.
- Application-defined key
- Only this CONNECT
- Up to 100 pairs
A Will is registered with the Broker during CONNECT, not set whenever Publish is pressed. A normal DISCONNECT should not publish it; abnormal connection loss and other triggers follow protocol and Broker behavior.

- Will Topic Name; 2. Offline payload; 3. JSON utility only; 4. Will delivery QoS; 5. Retained status.
- Will Topic Name
- Offline payload
- JSON utility only
- Will delivery QoS
- Retained status
Scroll the table sideways to see all columns.
| Setting | Default, limits, and use | New in V5? |
|---|---|---|
| Last-Will Topic | Initially empty. A valid Topic Name without + or #; no Topic means no registered Will | No |
| Last-Will Payload | Initially empty. Current form limit: 65,535 UTF-8 bytes. For example {"status":"offline"}; an empty payload also has meaning | No |
| QoS | Default 0, options 0/1/2. Governs the Broker's Will publication, subject to subscription and Broker capability | No |
| Retain Last-Will Message | Default off. On can preserve an offline status for later subscribers | No |
| Edit JSON | Edits the Will draft using the utility, not its QoS or protocol version | Tool feature |
| Format | Formats valid JSON. It does not mean the Broker requires JSON payloads | Tool feature |
| Open in JSON | Opens a JSON workspace for the draft, not an already-published Will | Tool feature |
QoS 1 can deliver duplicates. MQTT QoS 2 does not itself guarantee exactly one database write. Retain stores the last retained message for a Topic, not all history, and does not depend on a particular subscriber's session surviving.

- Wait before Will; 2. TTL after publish; 3. Describe the payload; 4. Reply routing; 5. Correlation bytes.
- Wait before Will
- TTL after publish
- Describe the payload
- Reply routing
- Correlation bytes
Scroll the table sideways to see all columns.
| V5 setting | Default or omitted behavior | Usage and purpose |
|---|---|---|
| Will Delay Interval | Seconds, 0 to 4,294,967,295, default zero; the product omits zero | Provides a brief interruption window. Publish when the delay elapses or the session ends, whichever is earlier; resuming the same session suppresses the pending Will |
| Message Expiry Interval | Seconds, 0 to 4,294,967,295; omission means no protocol TTL. The current product omits 0, so it cannot express the protocol's immediate-expiry zero here | Limits the Will's lifetime after publication, not the delay measured from connection loss |
| Content Type | Initially empty, a MIME type agreed by applications, such as application/json; no payload conversion | Helps the receiver interpret content; declaring JSON is not validation |
| Response Topic | Initially empty; a valid Topic Name without wildcards | Supplies response routing when an application uses that pattern; no automatic reply or subscription |
| Correlation Data | Initially empty; binary at protocol level. The current text input sends bytes such as request-7, not automatic Base64 decoding | Associates a response with its request; not a Client ID, sort key, or universal deduplication key |
The V5 specification also permits Will Payload Format Indicator and Will User Properties. The current New Client Will area has no independent controls for them. Do not label the publish-panel UTF-8 switch as a Will control, or CONNECT User Properties as Will metadata.
Will Delay must be considered with Session Expiry. If Expiry is zero, the session ends at disconnection, so a ten-second Will Delay alone cannot promise a ten-second notification grace period. The experiment retains the session longer than the delay and separately checks reconnection within that interval and failure to reconnect.
- Test Connection temporarily checks the current protocol and credentials. It does not save a new Client or establish a persistent connection. The current test registers no Will, publishes nothing, subscribes to nothing, and does not automatically reconnect.
- Cancel leaves the unsaved form. It does not undo earlier Broker-side connection or testing effects.
- Connect saves configuration and starts a real connection. Connected proves connection establishment, not subscription approval or message delivery.
Test Connection uses the real Client ID. It can take over an existing connection, trigger that connection's Will, or affect sessions and queued messages. A passed test does not verify publish, subscribe, Will permissions, or all quota settings. Broker transport testing and Client authentication testing are different entry points.

Client, Topic, Payload, QoS, and Retain exist in both versions. This is an unsent configuration example.
- Sending connection
- Topic Name only
- Application bytes
- Delivery QoS
- Last retained value
Client selects the sending connection. Topic is a Topic Name without subscription wildcards. Payload is application content; MQTT does not require JSON. QoS selects 0/1/2, and Retain controls the Topic's retained message. All exist in 3.1.1.

These properties belong to this PUBLISH. Content Type and UTF-8 do not replace business validation.
- Content description
- Message TTL seconds
- UTF-8, not JSON
- Per-message metadata

The reply route and correlation bytes are application conventions. An alias must stay within the peer allowance.
- Subscribe for replies
- Match the request
- Connection-local alias
- V5 sending client
Scroll the table sideways to see all columns.
| Publish property | Values and omitted behavior | V5 purpose and limits |
|---|---|---|
| Content Type | Optional UTF-8 string, for example application/json | Describes content, without automatically decoding, converting, or validating its business structure |
| Payload Format Indicator | Zero or omission means unspecified bytes; one means UTF-8 character data. The current switch is labeled UTF-8 | Describes encoding, not JSON validity or the utility's Base64 input mode |
| Message Expiry | Four-byte seconds value. Omission means no protocol TTL; the protocol's zero means immediate expiry | Limits messages not yet forwarded and retained storage; does not cancel work already underway in a receiving application |
| Response Topic | Optional valid Topic Name without wildcards | Tells the responder where to reply. Subscribe before sending the request |
| Correlation Data | Optional binary data, sent as bytes by the current text input | The responder returns the original bytes under application policy to distinguish concurrent requests |
| Topic Alias | From 1 up to the peer's advertised CONNACK allowance; zero is illegal. Omission uses the normal Topic | Mappings are connection-local. A protocol example with an empty Topic does not prove every UI can submit an empty Topic |
| User Properties | Repeatable Key/Value; current publish form limit is 100 pairs | Application metadata forwarded with the message, separate from CONNECT properties |
Why not continue putting everything in JSON? V3 applications can implement TTL, request IDs, and content types, but each needs its own payload convention. A Broker generally cannot enforce protocol expiry or routing using an arbitrary business convention. V5 standardizes the metadata container while leaving payload design open.
Message Expiry does not replace application-side timestamp checks. Topic Alias does not guarantee every connection saves bandwidth; inspect whether actual PUBLISH packets established and reused mappings.

V3 has Topic Filter and QoS but no standard MQTT 5 subscription option bits. Alert Monitor is separate.
- Wildcard Topic Filter
- Subscriber identity
- Read the SUBACK grant

Change one option at a time when testing. Subscription Identifier reports matching subscriptions, not unique message identity.
- Maximum requested QoS
- Suppress self echo
- Preserve Retain flag
- Replay only if new
- Which subscription?
Client selects the subscriber. A Topic Filter can use + for one level and # for subsequent levels. QoS requests the highest delivery level; read SUBACK for the grant. The following V5 options are not part of the standard 3.1.1 SUBSCRIBE format.
Scroll the table sideways to see all columns.
| Setting | Defaults and values | Why V5 adds it |
|---|---|---|
| No Local | Default off, bit 0/1; on suppresses messages originating from this client | Reduces self-echo in bridges and publish/subscribe clients; does not block other publishers or disable local networking |
| Retain as Published (RAP) | Default off; on preserves the publication's Retain flag, while off follows normal live-forwarding rules | Helps bridges preserve retained semantics; it does not decide whether stored retained messages are replayed on subscribing |
| Retain Handling (RH) | Default 0; zero requests retained replay on subscribe, one only for a new subscription, two no subscription-triggered retained replay | Avoids repeatedly processing old state; two does not block future live messages |
| Subscription Identifier | Optional, 1 to 268,435,455; zero is illegal | Identifies matching subscriptions on received PUBLISH packets, especially overlapping filters; not a Client ID or unique message ID |
For RH one, "new" means the Broker's subscription state, not that the user just opened the Client. If a tool unsubscribes before subscribing again, that is not an update to an existing subscription. The experiment directly repeats SUBSCRIBE through an auxiliary client to distinguish RH zero, one, and two.
Use $share/group/TopicFilter, for example $share/version-workers/versions/shared. For each matching message, the Broker chooses a subscriber in that group, providing work distribution. It does not promise strict round-robin, even distribution, or exactly-once business processing. The group and filter must satisfy shared-subscription syntax, and No Local must not be set to one for a shared subscription.

The group shares work; it does not promise equal distribution. Some Brokers also support this extension under V3.
- Group and Topic Filter
- Must be off for shared
- One group participant
MQTT 5 standardizes shared subscriptions, but some Brokers already offer them with 3.1.1. Do not claim V3 systems cannot distribute work; distinguish the standard from Broker extensions. Respect a CONNACK Shared Subscription Available declaration.
The tests use task-owned Mosquitto, EMQX, and the locally fixed Mqttable source Runtime on loopback. Auxiliary protocol clients handle steps the UI cannot precisely control, including delayed PUBACK and repeated SUBSCRIBE. Those results are not attributed to Mqttable button clicks. Packet capture is restricted to this laboratory's ports. The screenshot endpoint 22932 is a loopback recording proxy forwarding to Mosquitto on 22931; readers can connect directly to 22931. That recording proxy is not an MQTT 5 requirement.
With Mosquitto already installed on macOS or Linux, create a private, separate experiment directory. These commands do not overwrite a configuration. Port 22931 must be free; stop and choose another loopback port if it is occupied.
LAB_DIR="$(mktemp -d)"
printf '%s\n' "$LAB_DIR"
cat > "$LAB_DIR/mosquitto.conf" <<'CONF'
listener 22931 127.0.0.1
allow_anonymous true
persistence false
CONF
mosquitto -c "$LAB_DIR/mosquitto.conf"Anonymous access is for this local experiment, not public deployment. In Mqttable, create Broker mqtt://127.0.0.1:22931, then two distinct Client IDs for 3.1.1 and 5.0. Start with QoS 1 and Retain off, and wait for subscription confirmation before publishing.
- Disable Clean Session for V3. For V5, disable Clean Start and use a positive Session Expiry. Keep the Client ID stable.
- Subscribe to
versions/session, disconnect the subscriber normally, and publish QoS 1 from another connection. - Reconnect within the retention window. Check CONNACK Session Present and the queued message, not just the local subscription list.
- Disconnect V5 again and reconnect after expiry to check that the old session has ended.
- With a recoverable session, publish a short-TTL message while offline, wait beyond TTL, and reconnect. Then send a fresh message as the positive control.
In this source snapshot, Trace records contain ack_flags, while the inspector reads a different Session Present field name and may not display it. A missing UI row is not zero. Recovery is verified from actual packet flags and the low bit of the Trace record; the CONNACK screenshot below illustrates acceptance and receiving limits only.

These CONNACK limits describe what the Broker receives. Session Present is verified from actual flags, not a missing inspector row.
- Connection, not delivery
- Zero means accepted
- Broker alias allowance
- Broker receiving limits
Actual results and waiting windows appear in the verification table. A screenshot containing no messages does not prove expiry works; negative observations require timing and a successful delivery control.
These commands were tested with this run's Mosquitto 2.1.2. The first subscription creates a session and exits after the expected one-second timeout. Exit code 27 is not an authentication error; stop for other failures. A two-second message TTL followed by a five-second wait means recovery should not deliver stale-command.
# Keep a session for 30 seconds; exit 27 is the expected one-second timeout.
mosquitto_sub -h 127.0.0.1 -p 22931 -V mqttv5 \
-i article-cli-expiry -c -x 30 -q 1 -t versions/cli-expiry -W 1 -v \
|| [ "$?" -eq 27 ]
mosquitto_pub -h 127.0.0.1 -p 22931 -V mqttv5 -q 1 \
-t versions/cli-expiry -m stale-command \
-D PUBLISH message-expiry-interval 2
sleep 5
mosquitto_sub -h 127.0.0.1 -p 22931 -V mqttv5 \
-i article-cli-expiry -c -x 30 -q 1 -t versions/cli-expiry -W 1 -v \
|| [ "$?" -eq 27 ]Positive control: keep the following subscription running and publish fresh-command from a second terminal. It should arrive. An empty one-second observation by itself is not proof of expiry.
mosquitto_sub -h 127.0.0.1 -p 22931 -V mqttv5 \
-i article-cli-expiry -c -x 30 -q 1 -t versions/cli-expiry -C 1 -W 4 -vmosquitto_pub -h 127.0.0.1 -p 22931 -V mqttv5 -q 1 \
-t versions/cli-expiry -m fresh-command \
-D PUBLISH message-expiry-interval 2A separate observer subscribes to versions/will/#. The observed client uses a positive Session Expiry longer than Will Delay. A normal Disconnect sends no Will; abnormal loss followed by a wait beyond the delay produces one. Recovering the same session within the delay, with the same Client ID and Clean Start off, suppresses it. With Message Expiry on a retained Will, a later subscriber must not receive that expired state; a fresh publication verifies the path still works.
For request/response, subscribe the requester to versions/reply first. Publish a request with that Response Topic and Correlation Data request-7. The responder subscribes to versions/request, replies to the specified Topic, and returns the same correlation bytes. The Broker does not execute the business operation, and PUBACK is not the business response.

The received PUBLISH carries the correlation bytes and matching subscription ID. PUBACK alone would not prove this reception.
- Actual application reply
- Same request-7 bytes
- Matched subscription 7
- Inbound connection alias
The auxiliary flow-control receiver advertises Receive Maximum two and withholds PUBACK, then acknowledges one message to release budget. The size test advertises 128 bytes, publishes a small message, a 512-byte payload, and another small message. A sender's PUBACK is not proof of subscriber receipt.
The alias test checks both CONNECT and CONNACK budgets, the initial Topic mapping, and subsequent PUBLISH packets. Reconnection requires a new mapping.
Change subscription options individually: No Local compares self-publishing with a different connection; RAP compares the Retain bit on the same live retained publication; RH compares first and repeated subscriptions; Subscription Identifier is checked in received PUBLISH. Shared subscriptions require correct combined message identity and count, not a forced fifty-fifty split.
Scroll the table sideways to see all columns.
| Scenario | Result | Evidence boundary |
|---|---|---|
| Session recovery | V3/V5 Session Present true and queued QoS 1 delivery | Auxiliary clients; fixed IDs |
| Session expiry | V5 expiry 2 s; after 5 s disconnected, Session Present false | Not inferred from resubscription |
| Queued/retained expiry | Two-second stale messages absent; fresh controls delivered | Observation beyond TTL |
| Will publication/suppression | Normal close: none; abnormal loss: Will; same-session recovery suppresses it | Will Delay 1/2 s; session expiry 20 s |
| Will message expiry | Will observed; later subscriber does not receive expired retained status | Fresh state control |
| Request/response | Reply 21.5 returns request-7 correlation bytes | Auxiliary and managed Mqttable loops verified separately |
| Receive Maximum | Window 2: two before ACK; one ACK releases one more | Auxiliary receiver withholds PUBACK |
| Maximum Packet Size | 128-byte limit prevents 512-byte payload forwarding; small controls arrive | Sender PUBACK is not receipt |
| Bidirectional aliases | Broker budget 10; client budget 2; mappings reused | Separate directional budgets |
| No Local / RAP / RH | Self-echo suppressed; RAP differs; RH new/repeated behavior verified | Positive controls; repeated direct SUBSCRIBE |
| Subscription ID/shared subscriptions | Identifier 7 received; six jobs distributed without duplicates | No fairness or business exactly-once claim |
| Server disconnect | Same-ID takeover returns V5 DISCONNECT 0x8E | Actual Broker response |
| SCRAM-SHA-256 | Managed Mqttable connected; actual AUTH/AUTH/CONNACK 0x00 | Credentials + SecretRef + Compact MCP; not raw-submit acceptance |
| CLI expiry reproduction | Expected timeout exit 27; no stale command, fresh-command received | Published CLI arguments tested |
The SCRAM-SHA-256 experiment uses a separate EMQX 6.0.0 instance, a scram:built_in_database authenticator, and a synthetic user. Mqttable selects the same method. The tested connection uses a synthetic password stored through Credentials and a SecretRef created through Compact MCP; raw-password form submission is not claimed as accepted. Inspect real AUTH/CONNACK rather than treating a selected dropdown option as authentication success. This does not validate SHA-1, SHA-512, or reauthentication within an existing connection.

Both endpoints must use the same SCRAM method. A configured method is not proof of a successful AUTH exchange.
- AUTH needs MQTT 5
- Match SHA-256 policy
- Synthetic lab user
- Masked local credential

Read timestamps in chronological order: CONNECT, AUTH challenge, AUTH response, CONNACK. This proves connection authentication, not message permissions.
- Client starts CONNECT
- Broker challenge
- Client response
- Connection accepted
For rejection, distinguish MQTT 3.1.1 CONNACK return codes from MQTT 5 reason codes; exact values follow the Broker's observed policy. Duplicate Client ID takeover can also produce a server DISCONNECT 0x8E under V5. Reason String is optional: do not fabricate one when the Broker omits it. Use the error-code reference for meanings.
Scroll the table sideways to see all columns.
| Capability | Problem addressed | Boundary in this guide |
|---|---|---|
| Reason codes and Reason String | More explicit publish, subscribe, and disconnect outcomes | Not all reason codes are errors; diagnostic text is not a stable API |
| Server DISCONNECT | Lets the Broker explain why it closes a connection | Shows actual takeover, not invented refusal reasons |
| CONNACK Maximum QoS and Retain/Wildcard/Subscription Identifier/Shared Subscription Available | Advertises optional Broker capabilities before unsupported operations | Broker response properties, not another set of client toggles; absent optional attributes are not invented |
| Server Keep Alive | Lets the Broker state the desired keepalive interval | Not another client input field |
| Assigned Client Identifier | Returns a Broker-generated identity for later use | The Client ID generation button is not claimed to use it |
| Server Reference | Indicates an alternative server with applicable CONNACK/DISCONNECT reasons | Does not prove Mqttable automatically migrates a connection; redirect behavior is not tested here |
| AUTH and reauthentication | Supports challenge-response and authentication within a connection | Connection-phase SCRAM is tested; no claim of an initiating reauthentication UI |
Confirm the Broker and device SDK support V5, then use a non-production identity for a complete message loop. Changing a version string does not preserve every behavioral assumption.
- For V3 Clean Session on behavior, use V5 Clean Start on and Session Expiry zero.
- For offline recovery, retain the Client ID and choose Clean Start off plus a deliberate positive interval.
4,294,967,295means no protocol time-based expiry, not eternal survival through every Broker failure. - For time-sensitive commands, define Message Expiry and application timestamp checks. For noisy connection-status notifications, consider Will Delay with sufficient Session Expiry.
- For constrained receivers, configure Receive Maximum and Maximum Packet Size. Their direction matters; they are not a publishing-rate control.
- Introduce Response Topic, Correlation Data, No Local, RAP, RH, and Subscription Identifier when request/response, bridges, or overlapping subscriptions need them.
Choosing 3.1.1 does not make a system unreliable. Choosing 5.0 does not automatically repair authentication, reconnection, duplicate processing, or stale business data. Express requirements in configuration, then inspect CONNECT/CONNACK, SUBACK, PUBLISH, and real reception.
Does V5 require a different port? No. A listener decides which versions it accepts; a port and MQTT protocol version are different configuration layers.
Are QoS 2, Retain, and JWT new V5 features? No. QoS 2 and Retain exist in V3, and JWT can be ordinary MQTT Password material. V5 adds standard properties, enhanced authentication, and associated behavior.
Can Session Expiry, Message Expiry, Will Delay, and JWT exp replace each other? No. They govern disconnected sessions, message usefulness, Will publication timing, and token validity respectively.
Why is Response Information missing despite Request Response Info? The specification permits the Broker to omit it; response routing and correlation still require application agreement.
Does a restored subscription list prove session recovery? No. A client may have resubscribed. Inspect Session Present and queued delivery to distinguish local configuration from Broker state.
Continue with connection settings, publish and subscribe, Trace, and PCAP analysis. TLS, alerts, and scheduled messages have their own configuration boundaries rather than being MQTT-version differences.