MQTT 5 Maximum Packet Size Explained: Property 0x27

By | July 1, 2026

Every MQTT packet has a size — from a tiny 2-byte PINGREQ to a large PUBLISH carrying a firmware update. In MQTT 3.1.1, receivers had no way to tell senders what maximum packet size they could handle. A memory-constrained embedded gateway would just crash when a 10 MB PUBLISH arrived. A publisher had to guess: is this Server OK with big messages? A wrong guess meant unpredictable failures.

MQTT 5 fixed this with the Maximum Packet Size property. Both sides declare during connection setup exactly how large a packet they will accept. Violation triggers a clear DISCONNECT with Reason Code 0x95 (Packet too large) — no more mystery failures, no more guessing. Combined with Receive Maximum (which limits in-flight message count), Maximum Packet Size gives receivers full control over their memory commitment.

This article explains how Maximum Packet Size works, what actually counts toward the limit (spoiler: the whole packet, not just the payload), how to tune it for embedded through high-throughput deployments, and how it interacts with other MQTT 5 features.

What Maximum Packet Size is in one paragraph

Maximum Packet Size is a UINT32 property (0x27) that a party declares during MQTT 5 connection setup to specify the largest packet in bytes it will accept from the other party. The client sends it in CONNECT — telling the Server “don’t send me packets larger than N bytes.” The Server sends it in CONNACK — telling the client “don’t send me packets larger than M bytes.” Values are independent per direction. If a sender exceeds the receiver’s declared limit, the receiver responds with DISCONNECT carrying Reason Code 0x95 (Packet too large) and closes the connection. The limit applies to the entire MQTT packet — Fixed Header + Variable Header + Payload — not just the payload data. Absence of this property means “no explicit limit,” subject to the MQTT protocol’s absolute maximum of 268,435,455 bytes (~256 MB) derived from the Variable Byte Integer encoding of the Remaining Length field.

Why MQTT 5 added explicit packet size limits

MQTT 3.1.1 had no packet size property. This caused several categories of pain in production:

Pain 1: Unpredictable failures

An embedded gateway with 128 KB of RAM connects to a broker. Everything works fine — until one day someone publishes a 500 KB message. The gateway allocates memory to receive the packet, runs out of RAM, and either crashes or drops the connection silently. Nothing in the protocol warned the publisher that this was a problem.

Pain 2: Implementation-dependent behavior

Different MQTT 3.1.1 brokers had different implicit limits. Mosquitto might accept 256 MB packets by default; some embedded brokers might refuse packets over 8 KB. A client that worked fine against one broker might mysteriously fail against another with no protocol-level explanation.

Pain 3: No way to enforce policy

Cloud MQTT services wanting to prevent abuse (huge payloads consuming bandwidth) had no MQTT-native way to tell clients “you can only send messages up to X KB.” They had to enforce limits at higher layers (TLS termination, application layer) with confusing failure modes.

Pain 4: Memory planning was blind

Sizing a broker for expected traffic required knowing the largest possible message. Without a way to enforce that, brokers had to provision for worst-case scenarios — wasting memory in typical deployments and still risking failures in extreme cases.

MQTT 5’s Maximum Packet Size fixed all four: explicit per-connection declaration, clear failure mode when exceeded, portable across implementations, enforced at the protocol layer.

The Property (0x27) — the mechanism

Maximum Packet Size is one of the connection-negotiated properties exchanged during CONNECT/CONNACK.

FieldValue
Property Identifier0x27 (39 decimal)
TypeUINT32 (4 bytes, big-endian)
Valid range1 to 268,435,455 (~256 MB)
Invalid value0 (triggers Protocol Error 0x82)
AbsenceNo explicit limit (subject to protocol absolute max)
Appears inCONNECT (client→Server), CONNACK (Server→client)

Direction semantics

This is where engineers often confuse themselves:

  • Client’s Maximum Packet Size in CONNECT = the largest packet the Server may send to this client
  • Server’s Maximum Packet Size in CONNACK = the largest packet the client may send to the Server

The two values are independent. A memory-constrained embedded device might declare Maximum Packet Size = 4096 (refusing large inbound packets) while the Server declares Maximum Packet Size = 1048576 (accepting large outbound packets from clients). Each direction is governed separately.

How the sender uses it

The sender is responsible for tracking the declared limit and ensuring every packet it sends fits within it. Before serializing a PUBLISH, the sender computes the total encoded size:

Total packet size = Fixed Header + Variable Header + Payload

If this exceeds the receiver’s declared Maximum Packet Size, the sender must either:

  1. Refuse to send the packet (fail at the application layer)
  2. Split the payload into multiple smaller messages
  3. Compress the payload if possible
  4. Use Topic Aliases to reduce Variable Header size (for repeated topics)

The sender must not send an oversized packet — the spec doesn’t allow “try it and see.”

Default when absent

If Maximum Packet Size is absent from CONNECT or CONNACK, no explicit limit applies. The sender is still bounded by the absolute MQTT protocol maximum (~256 MB), but there’s no smaller per-connection limit.

Most well-designed MQTT 5 servers declare a Maximum Packet Size in CONNACK — even a generous one — to protect against memory-exhaustion attacks by malformed clients.

What actually counts toward packet size

This trips up many engineers. Maximum Packet Size limits the entire MQTT packet, not just the payload. Here’s what’s included:

For a PUBLISH packet

FIXED HEADER
  Byte 1:              Packet type + flags        1 byte
  Bytes 2-5:           Remaining Length (VBI)    1-4 bytes

VARIABLE HEADER
  Topic Name:          UTF-8 String              2 + N bytes
  Packet Identifier:   (QoS > 0 only)             2 bytes
  Properties Length:   Variable Byte Integer      1-4 bytes
  Properties:          Multiple properties        varies

PAYLOAD
  Application data                                varies

For a CONNECT packet

FIXED HEADER
  Byte 1:              Packet type                1 byte
  Bytes 2-5:           Remaining Length           1-4 bytes

VARIABLE HEADER
  Protocol Name:       "MQTT" as UTF-8            6 bytes
  Protocol Version:    5                          1 byte
  Connect Flags:                                  1 byte
  Keep Alive:                                     2 bytes
  Properties Length:                              1-4 bytes
  Properties:                                     varies

PAYLOAD
  Client Identifier    (UTF-8 String)             varies
  Will Properties      (if Will flag set)         varies
  Will Topic           (if Will flag set)         varies
  Will Payload         (if Will flag set)         varies
  User Name            (if User Name flag)        varies
  Password             (if Password flag)         varies

The “hidden” overhead

Engineers often calculate packet size by looking at payload size and forget these contributors:

  • Long topic namesfactory/site-A/line-3/station-5/sensor-42/temperature is 51 bytes alone
  • User Properties — each name+value pair adds ~50-200 bytes typically
  • Response Topic — for request/response, adds the response topic string
  • Correlation Data — up to 65,535 bytes
  • Authentication Data — for Enhanced Authentication, can be large
  • Reason String — for negative acknowledgements, adds human-readable text
  • Subscription Identifiers — Property 0x0B for advanced routing

For a 100-byte payload PUBLISH with:

  • Topic name (30 bytes)
  • 3 User Properties (~150 bytes)
  • Response Topic (25 bytes)
  • Correlation Data (16 bytes)
  • Standard properties overhead (~10 bytes)

The total encoded packet is roughly 331 bytes — over 3× the payload size.

Wildcards NOT applicable

Maximum Packet Size doesn’t check compressed size, TLS/TCP overhead, or anything below the MQTT layer. It’s strictly the encoded MQTT packet size before TLS encryption.

Failure mode — Reason Code 0x95 (Packet too large)

If a sender exceeds the receiver’s Maximum Packet Size, the receiver responds with DISCONNECT:

Receiver → Sender: DISCONNECT
  Reason Code: 0x95 (Packet too large)
  Properties (optional):
    Reason String: "Packet size 8500 bytes exceeds Maximum Packet Size of 4096"

The TCP connection is closed. The sender must reconnect to resume operation.

Sender responsibility vs receiver enforcement

Like Flow Control’s Receive Maximum, the primary responsibility is the sender’s: track the receiver’s declared limit and never exceed it. The receiver’s enforcement (DISCONNECT 0x95) is a safety net — a well-behaved sender never triggers this.

If your client regularly hits 0x95, either:

  • Your client isn’t tracking Maximum Packet Size at all
  • Your client miscalculates packet size (forgetting properties overhead)
  • Payloads are legitimately too large for the Server’s declared limit

Fixes depend on which case:

  • Not tracking: implement Maximum Packet Size awareness in the client
  • Miscalculating: correctly account for all packet components including properties
  • Legitimate need: request higher Maximum Packet Size from the Server, or split messages

What if the receiver won’t tell you the limit?

If Maximum Packet Size is absent from CONNACK, the Server hasn’t declared an explicit limit. But this doesn’t mean unlimited — implementation-specific defaults still apply. Sending very large packets is still risky if you don’t know the actual limit.

Best practice: assume conservative defaults (e.g., 128 KB) unless you know your Server can handle larger.

The 256 MB absolute maximum

MQTT’s Remaining Length field uses Variable Byte Integer (VBI) encoding. Each byte contributes 7 bits of value plus a 1-bit continuation flag. VBI supports up to 4 bytes, giving:

Maximum Remaining Length = 128^4 - 1 = 268,435,455 bytes ≈ 256 MB

Adding the 1-byte Fixed Header (packet type + flags):

Absolute maximum MQTT packet size = 268,435,455 + 5 = 268,435,460 bytes ≈ 256 MB

This is the hard ceiling — no MQTT 5 implementation can accept or send packets larger than this. Any Maximum Packet Size property declaring a value larger than 268,435,455 is invalid.

Practical implications

For typical MQTT deployments, the ~256 MB limit is theoretical — no real-world use case sends packets that large. Practical limits are much lower:

  • Embedded devices: 4 KB – 64 KB typical
  • Cloud IoT platforms: 128 KB – 1 MB typical
  • On-premises brokers: 1 MB – 10 MB typical
  • Bulk data transfer scenarios: 10 MB – 100 MB

For anything approaching 256 MB, MQTT is arguably the wrong protocol — HTTP with chunked encoding or dedicated file transfer protocols are more appropriate.

Tuning guidance by deployment

The right Maximum Packet Size depends heavily on your use case:

Embedded/constrained IoT devices

ConstraintTypical Maximum Packet Size
Small MCU (< 64 KB RAM)1 KB – 4 KB
Modest device (128 KB – 512 KB RAM)4 KB – 16 KB
Higher capacity IoT device (1 MB+ RAM)16 KB – 128 KB

Rule of thumb: allocate ~25% of available RAM for the largest expected message. Leave headroom for MQTT stack state, other buffers, and application code.

Cloud IoT / SaaS brokers

ServiceTypical Maximum Packet Size
AWS IoT Core128 KB (hard limit, not configurable)
Azure IoT Hub256 KB (hard limit)
Google Cloud IoT Core(Service deprecated 2023)
HiveMQ Cloud268 MB (spec absolute max, configurable)

Cloud services often enforce packet size limits at the protocol layer and reject over-limit connections upfront. Check your provider’s documentation.

Self-hosted brokers

Common defaults:

BrokerDefault Maximum Packet Size
HiveMQ Enterprise268,435,460 (unlimited, configurable down)
EMQX1 MB (configurable)
Mosquitto(implementation-specific, historically ~256 MB)
VerneMQConfigurable, no default limit

Self-hosted brokers give you full control. Common configurations:

  • Standard telemetry: 64 KB (fits almost any practical message)
  • Rich sensor data: 512 KB (fits images, structured payloads)
  • File transfer over MQTT: 10 MB – 100 MB (rare use case)
  • Firmware updates: 1 MB – 10 MB per chunk

High-throughput publishers

If your client will publish large payloads (bulk data, images, firmware updates), calculate:

Required Maximum Packet Size = 
  max_payload_size 
  + topic_name_length
  + expected_properties_overhead
  + protocol_overhead (typically ~20 bytes)

For safety, add 20% headroom to account for edge cases.

Memory budget calculation

Combined with Receive Maximum (in-flight limit), the worst-case memory commitment is:

Max receiver memory = Receive Maximum × Maximum Packet Size

For Receive Maximum = 100 and Maximum Packet Size = 1 MB, expect up to ~100 MB of in-flight message data at peak. This is why the two properties work together.

For deeper Flow Control coverage, see our MQTT 5 Flow Control article.

Interaction with Flow Control and other features

Maximum Packet Size interacts with several other MQTT 5 mechanisms:

Flow Control (Receive Maximum)

The two properties together bound receiver memory. Receive Maximum controls how many in-flight messages; Maximum Packet Size controls how big each one can be. Together they enforce a total memory budget.

Topic Aliases

Topic Aliases (Property 0x23) reduce packet size by replacing repeated topic name strings with 2-byte aliases. Especially valuable when your topic names are long and Maximum Packet Size is tight. See our MQTT 5 Topic Aliases article for the mechanics.

Example: a device with Maximum Packet Size = 4096 publishing to a 60-byte topic name saves 58 bytes per message after the first (using aliases). This effectively raises payload capacity from 4020 bytes to 4078 bytes per message.

User Properties

User Properties (Property 0x26) add name-value pair metadata. Each User Property typically adds 5-100+ bytes depending on name and value length. Heavy use of User Properties eats into your Maximum Packet Size budget significantly.

Enhanced Authentication

Authentication Data (Property 0x16) can be substantial for methods like SCRAM-SHA-512 or complex OAuth tokens. Client connections carrying JWT tokens can push CONNECT packets to several KB just for authentication content. Ensure Maximum Packet Size accommodates this.

For details, see our Enhanced Authentication in MQTT 5 article.

Session state

Session state (Session Expiry Interval, in-flight message tracking) is separate from Maximum Packet Size. But large numbers of retained in-flight messages during a resumed session can create bursts of large packets after reconnection — Maximum Packet Size still enforces per-packet limits at that time.

Common calculation examples

Example 1: Simple sensor telemetry

Topic: "sensors/temp/room-42"       (2 + 21 = 23 bytes)
Packet Identifier (QoS 1):           2 bytes
Properties Length:                    1 byte
Payload: {"value": 23.5, "ts": 12345678}  (~30 bytes)
Fixed Header + Remaining Length:      3 bytes

Total encoded packet: ~59 bytes

A Maximum Packet Size of 512 bytes is generous for this pattern.

Example 2: PUBLISH with User Properties

Topic: "orders/created"              (2 + 15 = 17 bytes)
Packet Identifier (QoS 1):           2 bytes
Properties Length:                    2 bytes
Property: User Property "trace-id"="a1b2c3d4-e5f6-..."  (5+42 = 47 bytes)
Property: User Property "tenant-id"="acme-corp"  (5+18 = 23 bytes)
Property: User Property "region"="us-west-2"    (5+15 = 20 bytes)
Property: Payload Format Indicator = 1           (2 bytes)
Property: Content Type = "application/json"      (5+18 = 23 bytes)
Payload: {"order_id": ..., "items": [...], ...} (500 bytes)
Fixed Header + Remaining Length:                  3 bytes

Total encoded packet: ~637 bytes

Properties overhead alone is 115 bytes — over 20% of the payload size.

Example 3: Large file transfer

Topic: "device/firmware/chunk"       (2 + 22 = 24 bytes)
Packet Identifier (QoS 2):           2 bytes
Properties Length:                    3 bytes
Property: Correlation Data (16 bytes UUID)  (19 bytes)
Property: User Property "chunk-num"="42"    (16 bytes)
Property: User Property "total-chunks"="100" (18 bytes)
Payload: <firmware chunk data>       (16,384 bytes)
Fixed Header + Remaining Length:      4 bytes

Total encoded packet: ~16,470 bytes

Need Maximum Packet Size of at least 20 KB with headroom for future property additions.

Example 4: CONNECT with credentials

Fixed Header + Remaining Length:      3 bytes
Protocol Name "MQTT":                 6 bytes
Protocol Version 5:                   1 byte
Connect Flags:                        1 byte
Keep Alive:                           2 bytes
Properties Length:                    2 bytes
Property: Session Expiry Interval    5 bytes
Property: Receive Maximum            3 bytes
Property: Maximum Packet Size        5 bytes
Property: Topic Alias Maximum        3 bytes
Property: Authentication Method "SCRAM-SHA-256"  (18 bytes)
Property: Authentication Data (SCRAM initial)    (~80 bytes)
Client Identifier "device-007-abcd" (2 + 16 = 18 bytes)

Total encoded CONNECT: ~147 bytes

Even for CONNECT with modest authentication, 512+ bytes of headroom is reasonable.

Backward compatibility with MQTT 3.1.1

MQTT 3.1.1 has no Maximum Packet Size property. Compatibility considerations:

MQTT 3.1.1 client to MQTT 5 Server

The Server downgrades to MQTT 3.1.1 semantics. Maximum Packet Size cannot be negotiated. The Server uses an implementation-specific default limit for inbound packets. Clients using MQTT 3.1.1 have no way to know this limit — they just risk connection drops if they send too-large packets.

MQTT 5 client to MQTT 3.1.1 Server

The client’s CONNECT returns CONNACK with Reason Code 0x84 (Unsupported Protocol Version), forcing the client to reconnect with MQTT 3.1.1. Once using MQTT 3.1.1, no Maximum Packet Size negotiation is available.

Mixed-version fleets

Servers supporting both MQTT versions typically enforce a common packet size limit implementation-side, applying it to all clients regardless of protocol version. MQTT 5 clients get to see the limit via Maximum Packet Size; MQTT 3.1.1 clients don’t but are subject to the same underlying limit.

For broader version comparison, see our MQTT 5 vs MQTT 3.1.1 Comparison article.

Common errors and troubleshooting

SymptomLikely causeWhat to check
DISCONNECT 0x95 on PUBLISHPayload too large for Server’s Maximum Packet SizeCheck Server’s declared limit; reduce payload or request higher limit
DISCONNECT 0x95 on CONNECTCONNECT packet larger than implicit Server limitReduce Client Identifier, credentials, Will Message size
Sporadic 0x95 failuresClient not calculating packet size correctlyInclude ALL properties in size calculation
0x95 on small payloadsHeavy User Properties overheadReduce number/size of User Properties
Client crashes on inbound messageClient’s declared Maximum Packet Size too small OR client doesn’t respect its own limitCheck client-side memory allocation logic
Firmware update fails at chunk NChunk size exceeds Maximum Packet SizeReduce chunk size or increase Maximum Packet Size
Some messages accepted, others rejectedProperty overhead varies by messageStandardize property usage or use higher limit

Frequently asked questions

What is MQTT 5 Maximum Packet Size?

Maximum Packet Size is a UINT32 property (0x27) that MQTT 5 parties exchange during connection setup to specify the largest packet in bytes they will accept. The client sends it in CONNECT (limiting the Server’s outbound packets); the Server sends it in CONNACK (limiting the client’s outbound packets). The limits are independent per direction. Exceeding the limit triggers DISCONNECT with Reason Code 0x95 (Packet too large).

What does Reason Code 0x95 mean?

Reason Code 0x95 means “Packet too large” — the receiver got a packet exceeding its declared Maximum Packet Size. It’s carried in DISCONNECT before the connection is closed. If your client sees 0x95 frequently, either your client isn’t tracking packet size correctly, your payloads are legitimately too large for the Server’s limit, or you’re forgetting to account for properties overhead in size calculations.

Does Maximum Packet Size include just the payload?

No. Maximum Packet Size limits the entire MQTT packet — Fixed Header, Variable Header, and Payload combined. Common overhead contributors include topic names (can be 30-60 bytes), User Properties (~50-200 bytes each), Response Topic, Correlation Data (up to 65,535 bytes), Content Type, and Authentication Data. A 100-byte payload with rich properties can easily be a 500+ byte packet.

What is the absolute maximum MQTT packet size?

The MQTT protocol’s absolute maximum is 268,435,455 bytes (~256 MB). This comes from the Variable Byte Integer encoding of the Remaining Length field, which supports up to 4 bytes of length. Adding the 1-byte Fixed Header, total packet size ceiling is 268,435,460 bytes. No MQTT 5 implementation can accept or send packets larger than this — Maximum Packet Size values above this are invalid.

What happens if Maximum Packet Size is not sent?

If the property is absent from CONNECT or CONNACK, no explicit per-connection limit applies. The sender is still bounded by the MQTT absolute maximum (~256 MB), but there’s no smaller limit declared. Implementations typically have internal default limits regardless — well-designed brokers declare Maximum Packet Size in CONNACK to make the limit explicit, even if it’s generous.

Can I set Maximum Packet Size to 0?

No. Setting Maximum Packet Size to 0 is invalid and triggers Protocol Error (Reason Code 0x82). The value must be at least 1. In practice, useful values are much higher — at minimum enough to fit CONNECT/CONNACK packets with basic properties (typically several hundred bytes).

How do I tune Maximum Packet Size for embedded devices?

For memory-constrained embedded devices, allocate roughly 25% of available RAM for the largest expected message. A device with 64 KB RAM might set Maximum Packet Size to 4-8 KB. A device with 512 KB RAM might use 16-64 KB. Balance against realistic payload needs — if you’ll never receive messages larger than 1 KB, don’t reserve 16 KB. Higher values use more memory but can accept larger messages without buffer overflows.

How do Flow Control and Maximum Packet Size work together?

They together bound receiver memory. Flow Control’s Receive Maximum limits how many in-flight QoS 1+2 messages exist simultaneously; Maximum Packet Size limits how big each one can be. Worst-case memory = Receive Maximum × Maximum Packet Size. For Receive Maximum = 100 and Maximum Packet Size = 1 MB, receivers must be prepared for ~100 MB of in-flight message data. Tune both together for your memory budget.

Do Topic Aliases help with Maximum Packet Size limits?

Yes. Topic Aliases replace repeated long topic name strings with 2-byte aliases, significantly reducing per-packet size after the first message for each topic. If your Maximum Packet Size is tight and you publish to topics with long names, Topic Aliases can effectively raise your payload capacity by reclaiming the bytes previously consumed by topic name repetition. Especially valuable on constrained networks.

Can Maximum Packet Size differ between client and Server?

Yes. Client and Server declare their own independent Maximum Packet Size values. The client’s value (in CONNECT) applies to Server→client packets. The Server’s value (in CONNACK) applies to client→Server packets. A constrained client might declare 4 KB while the Server accepts up to 1 MB — meaning the client sends large packets to the Server but can only receive small packets. This asymmetric configuration is common for gateways aggregating data from many devices.

What common properties contribute the most to packet size?

The heaviest contributors are typically: Authentication Data (up to several KB for complex tokens or SCRAM exchanges), Correlation Data (up to 65,535 bytes for structured correlation), User Properties (each name+value pair adds 5-200+ bytes, and many are often used), Topic Name (long hierarchical topics can be 40-80 bytes), Response Topic (adds another topic name), and Reason String (human-readable error descriptions in acknowledgements). For lean packets, minimize these — use Topic Aliases, short property names, and avoid unnecessary User Properties.

Does Maximum Packet Size apply to all MQTT packet types?

Yes. Maximum Packet Size applies to every packet type — PUBLISH, SUBSCRIBE, UNSUBSCRIBE, CONNECT, and all acknowledgement types (PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK, DISCONNECT, AUTH). PUBLISH is the most common cause of hitting the limit because of variable payload sizes, but CONNECT can also hit the limit with heavy authentication or Will Message content. SUBSCRIBE with many topic filters can also be substantial.

Should MQTT clients calculate expected packet size before sending?

Yes, when close to limits. Well-behaved MQTT 5 clients should track the Server’s declared Maximum Packet Size and calculate expected packet size before serializing. For most typical messages this is overkill (packets are far below limits), but for large payloads or heavy properties usage, size calculation prevents surprise DISCONNECT 0x95 errors. The alternative — try sending and see if disconnected — creates unpredictable failures.

Author: Zakaria El Intissar

I've spent 13 years in power system automation, electrical protection, and SCADA communication, as an automation and industrial computing engineer. ScadaProtocols.com is where I turn what I've learned on site into plain guides and working tools — so other engineers can decode, analyze, and troubleshoot industrial communication protocols without the guesswork.