Repository navigation
[feat] Tracking issue MQTTv5 #821
Description
The features that doesn't require changes on persistences are:
- Reason code on all ACKs #822 — landed in feat: MQTT 5.0 reason codes & reason strings on ACKs (#822, #823, #1092) #1100
- Reason string on all ACKs #823 — partial (Reason String on PUBACK/PUBREC only; feat: MQTT 5.0 reason codes & reason strings on ACKs (#822, #823, #1092) #1100)
- Message expiry: the lifetime of the Will Message in seconds #824
- Server disconnect #825
- Payload format and content type (this should be already handled by mqtt-packet we just have to forward it) #826
- Request / Response #827
- Subscription id (persistence
addSubscriptionstores the entire sub packet so we don't have to make edits on that side) #828 — partial - Flow control #829 — partial
- User properties (this should be already handled by mqtt-packet we just have to forward it) #830
- Maximum Packet Size #831
- Optional Server feature availability #832
- Enhanced authentication #833
- Subscription options: I think this should already be implemented, expecially the noLocal flag but we should check this #834
- Will delay: checking the
putWillwe store the entire packet in persistence so no change is needed on that part #835 - Server Keep Alive #836
- Assigned ClientID #837
- Server reference #838 — Server Reference (landed in feat: MQTT 5.0 Server Reference / connect-time redirect (#838) [stacked on #1102] #1115)
- Request / Response Information (CONNECT 0x19 → CONNACK 0x1A) #1091 — Request / Response Information (landed in feat: MQTT 5.0 Request / Response Information (#1091) [stacked on #1100] #1102)
- Request Problem Information (CONNECT 0x17) #1092 — Request Problem Information (landed in feat: MQTT 5.0 reason codes & reason strings on ACKs (#822, #823, #1092) #1100; gates Reason string on all ACKs #823/User properties (this should be already handled by mqtt-packet we just have to forward it) #830)
The ones that require changes on persistences:
- Session expiry: we actually don't have storage support for this #839 — partial (in-memory only; no cross-restart durability)
- Shared subscriptions #841 — single-instance only (not cluster-safe)
- Topic alias #840 — inbound only (topic alias is per-connection; doesn't actually need persistence)
Development status — mqttv5 branch / PR #1088
Most of MQTT 5.0 has landed on the mqttv5 branch: #1088 (feat/mqtt5) was merged on 2026-06-30 (merge commit e7d0ce9) after eight rounds of review. MQTT 3.1/3.1.1 behaviour is unchanged. Tests live in test/mqtt5.js (40 tests, driving a real mqtt@5 client over TCP). Note: #1088 targeted mqttv5, not the default branch, so the per-feature issues it referenced are not auto-closed — the checklist above tracks their status until mqttv5 merges to release under #194.
Companion releases (resolved): the gating packages are published and package.json now points at published ranges — aedes-packet@^4.0.1 (moscajs/aedes-packet#192 — preserve properties/messageExpiry) and aedes-persistence@^10.3.1 (moscajs/aedes-persistence#108 — persist subscriptionIdentifier). The overrides shim has been removed; the scripts/check-no-git-deps.js release guard is no longer blocked (no git deps remain).
Update — PR #1100 (2026-07-03): granular ACK reason codes (#822), Reason Strings on ACKs (#823), and Request Problem Information gating (#1092) landed on mqttv5 (merge 0f59242). A denied v5 PUBLISH now returns 0x87 (Not authorized) on PUBACK/PUBREC with the handler's error.message as the Reason String — suppressed when the client connected with Request Problem Information = 0 ([MQTT-3.1.2-29]); a denied v5 SUBSCRIBE returns SUBACK 0x87; PUBREL/PUBCOMP carry a Success reason code; and a rejecting PUBREC (≥ 0x80) terminates the QoS 2 flow without a PUBREL, releasing the stored outgoing packet id ([MQTT-5.0 §4.3.3]). Reason Strings are wired on PUBACK/PUBREC only — SUBACK/UNSUBACK/PUBREL/PUBCOMP still omit them, so #823 remains partial. A pinned Eclipse Paho interoperability workflow (tools/mqtt-compat/) tracks the conformance % (MQTT 5.0 at 62%, MQTT 3.1.1 at 100%).
Update — PR #1102 (2026-07-06): Request / Response Information (#1091) landed on mqttv5 (merge a025504). When a client sets Request Response Information on CONNECT ([MQTT-3.1.2-28], §3.1.2.11.6), the broker returns Response Information in the CONNACK (§3.2.2.3.15, server MAY) — but only when the new broker option responseInformation is configured (a static string or a (client) => string | undefined function for a per-client base; null default = never returned). Returned only on a successful CONNACK; a resolver that throws degrades to omit + surfaces on the clientError event. Broker-core only — no persistence changes, cluster-safe.
Update — PR #1115 (2026-07-06): Server Reference / connect-time redirect (#838) landed on mqttv5 (merge 8fb6bdc). A preConnect/authenticate hook can redirect a v5 client by rejecting with an error carrying a serverReference (and an optional reasonCode): the rejection CONNACK then carries 0x9C (Use another server) — or 0x9D (Server moved) when the hook sets err.reasonCode — plus the serverReference property (§4.11). A serverReference paired with a non-redirect reason code is clamped to 0x9C, and the property is dropped for non-v5 clients. Mid-session redirect already worked via client.disconnect({ reasonCode, properties: { serverReference } }) — now covered by a test. Broker-core only — no persistence changes, cluster-safe.
Persistence & cluster classification
The features split three ways by what they touch beyond the broker core:
A. Need aedes-packet changes (the packet object that travels through the emitter + persistence must preserve the new fields): property pass-through — #826, #827, #830 — and Message Expiry #824 (messageExpiry must survive storage/forwarding). Covered by moscajs/aedes-packet#192.
B. Need aedes-persistence changes (and round-trip support in the mongodb / redis / level implementations):
- Subscription id (persistence
addSubscriptionstores the entire sub packet so we don't have to make edits on that side) #828 Subscription Identifier — must be stored per-subscription and round-tripped by every backend (feat: persist MQTT 5.0 subscription identifier aedes-persistence#108; backends already store the whole packet, so a conformance test rather than backend code is expected). - Session expiry: we actually don't have storage support for this #839 Session Expiry — needs a persisted expiry deadline + a restart-time reaper. Not done — currently in-memory timers only.
- Shared subscriptions #841 Shared Subscriptions — needs
addSharedSubscription/group-membership storage; cluster-correct delivery additionally needs global group state inmongodb/redis.
C. No persistence change — broker core / per-connection: #822, #823, #825, #829, #831, #832, #833, #834, #836, #837, #838, #840.
Special cluster handling required:
- Shared subscriptions #841 Shared subscriptions — group membership is per-instance, so a shared message is delivered once per instance holding a group member instead of once cluster-wide. Cluster-correct delivery needs global membership + deterministic recipient selection coordinated via the persistence/emitter layer (
mqemitter-redis/-mongodb). - Session expiry: we actually don't have storage support for this #839 Session Expiry & Will delay: checking the
putWillwe store the entire packet in persistence so no change is needed on that part #835 Will Delay — enforced by per-instance in-memory timers; not durable across a broker restart or coordinated across the cluster (needs persisted deadlines + a reaper). - Everything else is cluster-safe as-is: per-connection features (Maximum Packet Size #831/Server Keep Alive #836/Assigned ClientID #837/Topic alias #840/Server disconnect #825/Flow control #829/Enhanced authentication #833/Server reference #838, reason codes) are local to the owning instance; property forwarding (Payload format and content type (this should be already handled by mqtt-packet we just have to forward it) #826/Request / Response #827/User properties (this should be already handled by mqtt-packet we just have to forward it) #830), Subscription Identifiers (Subscription id (persistence
addSubscriptionstores the entire sub packet so we don't have to make edits on that side) #828, attached at delivery by the subscribing instance) and message/retained expiry (Message expiry: the lifetime of the Will Message in seconds #824, absolute timestamps carried on the packet) ride the shared emitter + persistence correctly.
Conformance review (vs. OASIS MQTT 5.0)
Status: ✅ implemented & conformant · 🟡 partial · ❌ missing ·
Persistence: pkt = needs aedes-packet · persist = needs aedes-persistence (+ mongodb/redis/level) · — = core only.
Cluster: ✅ cluster-safe ·
| # | Feature | Status | Persistence | Cluster | Notes |
|---|---|---|---|---|---|
| #822 | Reason code on ACKs | ✅ | — | ✅ | Landed #1100. PUBACK/PUBREC 0x87 on authz failure; SUBACK failure 0x87 (v5) / 0x80 (v3/v4); PUBREL/PUBCOMP carry Success; rejecting PUBREC (≥0x80) ends QoS 2 with no PUBREL + packet-id release; CONNACK/UNSUBACK/server-DISCONNECT carry codes. Minor: PUBACK/PUBREC emit only 0x87 (not other granular failure codes). |
| #823 | Reason String on ACKs | 🟡 | — | ✅ | Landed #1100 (partial). reasonString from the handler's error.message on PUBACK/PUBREC, gated by Request Problem Information ([MQTT-3.1.2-29]). SUBACK/UNSUBACK/PUBREL/PUBCOMP still omit it. |
| #824 | Message Expiry Interval | ✅ | pkt | ✅ | Recomputed/dropped on queued + retained delivery; will-msg expiry ok. Minor: not decremented on the live path (wait ≈ 0). |
| #825 | Server disconnect | ✅ | — | ✅ | 0x8E/0x8B/0x95/0x94/0x82, v5-only; inbound 0x04 publishes will, 0x00 discards. |
| #826 | Payload format + content type | ✅ | pkt | ✅ | Forwarded transparently. |
| #827 | Request / Response | ✅ | pkt | ✅ | Response Topic + Correlation Data forwarded; Response Topic wildcard rejected ([MQTT-3.3.2-14]). |
| #828 | Subscription Identifier | 🟡 | persist | ✅ | Validated/persisted/echoed for single match; retained-on-subscribe now echoes the SI. Multi-match still delivers only one SI ([MQTT-3.3.4-4]) — deferred, documented limitation. |
| #829 | Flow control (Receive Maximum) | 🟡 | — | ✅ | ⏭️ defer (invasive to delivery hot path; advisory documented). Parsed (default 65535), 0 rejected, advertised. Outbound in-flight not capped (§4.9). |
| #830 | User Properties | ✅ | pkt | ✅ | Forwarded; preserved on the SI-merge fan-out. |
| #831 | Maximum Packet Size | ✅ | — | ✅ | Advertised; inbound oversized rejected pre-buffer (0x95). Outbound size-split advisory. |
| #832 | Optional feature availability | ✅ | — | ✅ | Max QoS/Retain/Wildcard/Sub-ID advertised correctly. Shared-sub flag → see #841. |
| #833 | Enhanced authentication | 🟡 | — | ✅ | CONNECT Authentication Method now rejected with 0x8C (§4.12). ⏭️ defer full AUTH packet flow (re-auth 0x18/0x19). |
| #834 | Subscription options | ✅ | — | ✅ | Max QoS ✅, No Local ✅, Retain As Published ✅, Retain Handling 0/1/2 ✅ ([MQTT-3.8.3-2]). |
| #835 | Will delay | 🟡 | persist | Will persisted (no schema change); reconnect cancels. Delay timer is per-instance (cross-broker will-sweep partially covers). WillDelayInterval Will-property leaks into the delivered PUBLISH (rejected by strict v5 clients) — surfaced by the #1094 Paho workflow. |
|
| #836 | Server Keep Alive | ✅ | — | ✅ | Imposed when unset/over-limit; echoed in CONNACK. |
| #837 | Assigned Client Identifier | ✅ | — | ✅ | Generated + echoed only on empty client id. |
| #838 | Server reference | ✅ | — | ✅ | Landed #1115. preConnect/authenticate redirect via an error serverReference → rejection CONNACK 0x9C/0x9D + serverReference property (§4.11); non-redirect reason code clamped to 0x9C; property dropped for non-v5. Mid-session redirect via client.disconnect(). |
| #839 | Session Expiry Interval | 🟡 | persist ❌ | Correct within a running broker; inbound-DISCONNECT expiry validation now enforced ([MQTT-3.14.4-3]). ⏭️ defer cross-restart persistence (needs schema + reaper) — in-memory timers only. | |
| #840 | Topic Alias | 🟡 | — | ✅ | ⏭️ defer (outbound is optional / MAY). Inbound ✅ (resolve/register/strip/alias-0 + over-max reject, per-connection reset). Outbound ❌ (broker-assigned). |
| #841 | Shared Subscriptions | 🟡 | persist | ❌ | $share SUBSCRIBE now refused with 0x9E ([MQTT-3.2.2-23]). ⏭️ defer cluster-aware feature; single-instance impl on the sharedsubs branch (persistence-backed, not cluster-safe). #1088 advertises sharedSubscriptionAvailable: false. |
| #1091 | Request / Response Information | ✅ | — | ✅ | Landed #1102. CONNECT Request Response Information 0x19 ([MQTT-3.1.2-28]) → CONNACK Response Information 0x1A (§3.2.2.3.15), returned only when the client requests it and the broker sets the new responseInformation option (static string or (client) => string | undefined; null default = never). A throwing resolver degrades to omit + clientError. Distinct from #827 (per-message Response Topic) and #832 (capability flags). |
| #1092 | Request Problem Information | ✅ | — | ✅ | Landed #1100. CONNECT 0x17 ([MQTT-3.1.2-29]) now suppresses the #823 Reason String on PUBACK/PUBREC when set to 0. Absent ⇒ enabled; wire-0 ⇒ suppressed. |
Triage — complete in #1088 vs. defer
Principle: fix in #1088 anything where the PR already advertises or accepts a capability but then mishandles it (spec violation / misleading behavior). Defer net-new scope, persistence-schema, and cluster work. Legend: 🔧 #1088 · 🤔 judgment · ⏭️ defer.
✅ Completed in #1088 (landed in ceed520, verified against source):
- Retain Handling 1/2 (Subscription options: I think this should already be implemented, expecially the noLocal flag but we should check this #834) — [MQTT-3.8.3-2].
rh=2no longer sends retained on subscribe;rh=1only for a brand-new subscription (subscribe.js). $share→0x9Erejection (Shared subscriptions #841) — [MQTT-3.2.2-23]. A v5$share/...SUBSCRIBE is refused with0x9Einstead of becoming a dead literal subscription.- Inbound DISCONNECT Session-Expiry validation (Server disconnect #825/Session expiry: we actually don't have storage support for this #839) — [MQTT-3.14.4-3]. A non-zero Session Expiry on DISCONNECT is rejected when CONNECT declared
0. - Reject unsupported Authentication Method
0x8C(Enhanced authentication #833 guard) — §4.12. A CONNECT carryingauthenticationMethodis rejected with0x8Cinstead of a silent password downgrade. - Retained-on-subscribe SI echo (Subscription id (persistence
addSubscriptionstores the entire sub packet so we don't have to make edits on that side) #828, part) — [MQTT-3.3.4]. Retained deliveries now carry the SUBSCRIBE Subscription Identifier. - Response Topic wildcard validation — [MQTT-3.3.2-14]. A PUBLISH with a wildcard Response Topic is rejected.
✅ Landed in #1100 (mqttv5, merge 0f59242):
- Granular ACK reason codes (Reason code on all ACKs #822) — PUBACK/PUBREC
0x87, SUBACK0x87(v5), PUBREL/PUBCOMP Success, and rejecting-PUBREC QoS 2 termination with packet-id release ([MQTT-5.0 §4.3.3]). - Reason String on ACKs (Reason string on all ACKs #823, partial) — handler
error.messagesurfaced on PUBACK/PUBREC. - Request Problem Information gating (Request Problem Information (CONNECT 0x17) #1092) — [MQTT-3.1.2-29]. Reason String suppressed on PUBACK/PUBREC when the client set RPI = 0.
✅ Landed in #1102 (mqttv5, merge a025504):
- Request / Response Information (Request / Response Information (CONNECT 0x19 → CONNACK 0x1A) #1091) — [MQTT-3.1.2-28] / §3.2.2.3.15. CONNACK Response Information returned when the client requests it and the new broker
responseInformationoption is set (static string or per-client function;nulldefault = never). A throwing resolver degrades to omit +clientError.
✅ Landed in #1115 (mqttv5, merge 8fb6bdc):
- Server Reference / connect-time redirect (Server reference #838) — §4.11.
preConnect/authenticateredirect via an error carryingserverReference→ rejection CONNACK0x9C(Use another server) /0x9D(Server moved); a non-redirect reason code paired with a reference is clamped to0x9C; property dropped for non-v5 clients. Mid-session redirect viaclient.disconnect({ reasonCode, properties: { serverReference } }).
🤔 Judgment call:
- Multiple matching SIs collapsed to one (Subscription id (persistence
addSubscriptionstores the entire sub packet so we don't have to make edits on that side) #828) — [MQTT-3.3.4-4]. Strictly, one delivery should carry all matching subscription identifiers;dedupe()drops all but one. The fix reaches into the dedupe/delivery core (medium effort, real regression surface, low real-world hit rate). Lean: defer with a documented limitation + dedicated issue, unless strict conformance is wanted now.
⏭️ Defer to follow-ups (net-new scope / persistence / cluster / spec-optional):
- Shared subscriptions #841 full cluster-aware shared subscriptions —
sharedsubsrewrite + global group state inmqemitter-redis/-mongodb. - Session expiry: we actually don't have storage support for this #839 cross-restart session-expiry persistence — schema + mongodb/redis/level round-trip + reaper.
- Flow control #829 outbound Receive Maximum enforcement — invasive to the shared delivery hot path; advisory-only documented.
- Enhanced authentication #833 full enhanced auth (AUTH packet flow).
- Topic alias #840 outbound Topic Alias — spec-optional. (Reason code on all ACKs #822 granular ACK reason codes landed in feat: MQTT 5.0 reason codes & reason strings on ACKs (#822, #823, #1092) #1100; Reason string on all ACKs #823 Reason String on ACKs landed partial in feat: MQTT 5.0 reason codes & reason strings on ACKs (#822, #823, #1092) #1100 — PUBACK/PUBREC only, remaining ACK types outstanding.)
(#1091 Request / Response Information landed in #1102; #1092 Request Problem Information landed in #1100, now gating #823.)
Status generated from a spec-conformance audit of
mqttv5@ PR #1088 head (276cb2e), updated for #1100 (0f59242), #1102 (a025504) and #1115 (8fb6bdc). Shared-subscription code currently lives on the separatesharedsubsbranch (single-instance, pre-v5). Items marked 🟡/❌/⚠️ are the remaining work toward full v5 conformance (#194).
Activity
feat: MQTT 5.0 Assigned Client Identifier and Server Keep Alive
docs: note the MQTT 5.0 multi-Subscription-Identifier limitation (def…
feat: MQTT 5.0 support (#1088)
robertsLando commentedon Jun 30, 2026
✅ #1088 merged into
mqttv5on 2026-06-30 (merge commite7d0ce9).package.jsonnow uses published ranges (aedes-packet@^4.0.1,aedes-persistence@^10.3.1); theoverridesshim and the git-dep release block are gone.mqttv5(not the default branch), the per-feature issues it referenced were not auto-closed — the checklist at the top continues to track them untilmqttv5lands for release under [feat] Mqtt v5 support #194.The development-status section above has been updated to reflect the merge.
BenjaminDobler commentedon Jun 30, 2026
Proposed sequence for the remaining no-persistence items
Per @robertsLando's suggestion (start with the ones that don't touch persistence). Grouped into reviewable PRs against
mqttv5, ordered by conformance value × independence. All of these are broker-core only and cluster-safe.PR 1 — Reason codes & reason strings on ACKs (#822, #823, #1092)
reasonStringto ACK packets (PUBACK / PUBREC / PUBREL / PUBCOMP / SUBACK / UNSUBACK / server-DISCONNECT).requestProblemInformation = 0→ suppressreasonStringanduserPropertieson every packet except PUBLISH / CONNACK / DISCONNECT ([MQTT-3.1.2-29]).0x00; per-topic SUBACK failure codes instead of the coarse0x80; PUBACK/PUBREC codes beyond0x87.PR 2 — Request / Response Information (#1091)
CONNECT
0x19→ CONNACKresponseInformation0x1A. Small and standalone; optional (server MAY, §3.2.2.3.15) but cheap. Needs a small operator hook (broker option/callback) to supply the response-topic base.PR 3 — Server Reference (#838)
serverReference(0x1C) on CONNACK (0x9Cuse-another-server) and DISCONNECT (0x9C/0x9Dserver-moved). DISCONNECT already carries it viaclient.disconnect({ reasonCode, properties: { serverReference } }); the new part is a tiny reject-with-reference path at connect.Deferred (happy to propose separately when you want them)
0x18/0x19) — larger, design-heavy.addSubscriptionstores the entire sub packet so we don't have to make edits on that side) #828 multiple matching Subscription Identifiers — touches the dedupe/delivery core (documented limitation today).putWillwe store the entire packet in persistence so no change is needed on that part #835 durable will delay.Does this order work? I'd start with PR 1. I'll align each PR with your mqttv5 e2e compatibility workflow so the tests cover features as they land — and shout if you'd rather I sequence around what your e2e suite checks first.
robertsLando commentedon Jun 30, 2026
Yes go
test(mqtt-compat): mark server_topic_alias + subscribe_identifiers as…
feat: MQTT 5.0 Request / Response Information (moscajs#1091)
feat: MQTT 5.0 Server Reference / connect-time redirect (moscajs#838)
ci: MQTT 5.0 + 3.1.1 compatibility workflow (Paho interop) (#1094)
feat: MQTT 5.0 reason codes & reason strings on ACKs (moscajs#822, mo…
feat: MQTT 5.0 Request / Response Information (moscajs#1091)
feat: MQTT 5.0 Server Reference / connect-time redirect (moscajs#838)
feat: MQTT 5.0 Request / Response Information (moscajs#1091)
feat: MQTT 5.0 Server Reference / connect-time redirect (moscajs#838)
feat: MQTT 5.0 Request / Response Information (moscajs#1091)
feat: MQTT 5.0 Server Reference / connect-time redirect (moscajs#838)
feat: MQTT 5.0 reason codes & reason strings on ACKs (#822, #823, #1092…
feat: MQTT 5.0 Request / Response Information (moscajs#1091)
feat: MQTT 5.0 Server Reference / connect-time redirect (moscajs#838)
feat: MQTT 5.0 Request / Response Information (#1091) [stacked on #1100…
feat: MQTT 5.0 Server Reference / connect-time redirect (moscajs#838)
feat: MQTT 5.0 Server Reference / connect-time redirect (#838) [stack…
BenjaminDobler commentedon Jul 6, 2026
Next sequence — remaining MQTT 5.0 work
The no-persistence-first batch is all merged 🎉 (#1100, #1102, #1115). Proposing the next steps, grouped and ordered by value × independence × risk. Base is
mqttv5; each item is its own reviewable PR.Phase A — close the remaining Paho v5 compat gaps (broker-core, cluster-safe)
Each of these currently sits in
EXPECTED_GAPSintools/mqtt-compat/run_compat.py; landing it flips a⚠️ expected gapinto a pass and lifts the reported MQTT 5.0 compat %:addSubscriptionstores the entire sub packet so we don't have to make edits on that side) #828 — multiple matching Subscription Identifiers [MQTT-3.3.4-4] →test_subscribe_identifiers. Today a delivery matching several of a client's overlapping subscriptions echoes only one SI (the documented limitation); this delivers all matching ones. Touches the dedupe/delivery path, no persistence. Suggest starting here — clearest conformance win, smallest blast radius.test_server_topic_alias. Inbound aliases already work; this assigns aliases on outbound PUBLISH per connection. Per-connection state, moderate hot-path.test_flow_control1. Cap in-flight QoS 1/2 toward each client. The most invasive of the three (shared delivery hot path) — deferred originally for exactly that reason — so I'd do it last and benchmark it.Phase B — Enhanced Authentication (#833), independent feature
Full
AUTH-packet flow (§4.12): CONNECTAuthentication Method→AUTH(0x18 continue) exchange → CONNACK, plus re-auth (0x19). Today an auth-method CONNECT is rejected with0x8C. Needs a broker auth-exchange hook (SASL / token style). No persistence, cluster-safe, and not tied to a Paho compat test, so I've split it out. Higher design surface — happy to post a short hook-API proposal for sign-off before writing code.Phase C — persistence / cluster (multi-repo, later track)
These ripple into
aedes-persistence+ the mongodb/redis/level backends and/or need cluster coordination, so best treated as a separate track once A/B settle:putWillwe store the entire packet in persistence so no change is needed on that part #835 durable Will Delay — persisted delay deadline + reapertest_shared_subscriptions— global group membership + deterministic recipient selection viamqemitter-redis/-mongodbDoes this order work? I'd kick off with #828 unless you'd rather I clear all three Phase-A compat gaps first and leave #833 for after. For #833 I'll send a short hook-API sketch before implementing. 👍
robertsLando commentedon Jul 6, 2026
I would work on: #823 #829 #833 #840 first and then start with the once that require persistence changes
robertsLando commentedon Jul 6, 2026
let's clear all the no-persistence work before opening the persistence/cluster track. Two reasons it's the right cut: every such PR stays single-repo and cluster-safe (no
aedes-persistence+ mongodb/redis/level coordination), and each one flips a PahoEXPECTED_GAPSentry into a pass, so the reported MQTT 5.0 compat % keeps climbing as visible progress.Worth noting the two plans barely disagree — @BenjaminDobler's Phase A + Phase B are already all broker-core/cluster-safe, and only Phase C touches persistence. The one thing to correct: the batch isn't quite "all merged" yet.
#823 is still partial. Reason String landed on PUBACK/PUBREC only (#1100); SUBACK/UNSUBACK/PUBREL/PUBCOMP still omit it. That's pure broker-core, no persistence — so it belongs in this batch
Reconciling both lists against the table, the complete no-persistence set is:
addSubscriptionstores the entire sub packet so we don't have to make edits on that side) #828 — multiple matching Subscription Identifiers [MQTT-3.3.4-4]. Storage already landed; the remaining multi-match fix is dedupe/delivery-path only, so it's core-only despite the "persist" tag on the row.On ordering inside the batch I'd keep @BenjaminDobler's risk-based sequencing:
addSubscriptionstores the entire sub packet so we don't have to make edits on that side) #828 / Topic alias #840 / Reason string on all ACKs #823 are the clean, low-blast-radius compat-gap wins — good to start here.Then #839 / #835 / #841 as one coherent multi-repo persistence/cluster epic once the above settles. 👍
robertsLando commentedon Jul 6, 2026
FYI aedes@2.0.0-beta.1 is out now 🎉
feat: MQTT 5.0 Reason String on the remaining ACKs (#823) + PUBCOMP 0…