MQTT broker connection quotas decide how many clients you can attach, how fast they may publish and how large each message can be. This guide explains every common quota on a managed broker, how MQTT 3.1.1 and MQTT 5 brokers signal that you have hit one, and how to write clients that stay comfortably inside the limits of your plan.
Why Managed Brokers Enforce Quotas
A managed broker is shared infrastructure, even when you have a dedicated cluster. Memory, CPU, network bandwidth and file descriptors are finite, and a single misbehaving client, such as firmware stuck in a tight publish loop or a reconnect storm after a Wi-Fi outage, can degrade service for everyone else on the same machines. Quotas turn those finite resources into explicit, predictable limits.
On a multi-tenant service, quotas are also how isolation works in practice. ConnectMQ, for example, applies per-plan quotas, flood protection and IP blocking after repeated failed logins so that one tenant's problem stays that tenant's problem. If you are new to the model, our explainer on what an MQTT broker does covers the basics of how clients and brokers interact.
The Common MQTT Broker Quotas
Most providers enforce some combination of the following. Names differ, but the concepts are the same everywhere.
| Quota | What it counts | Typical symptom when exceeded |
|---|---|---|
| Concurrent connections | Open client sessions at the same moment | New CONNECT is refused |
| Connection rate | New connections per second or minute | Reconnects fail during storms |
| Message rate | Publishes per second per client or account | Client is throttled or disconnected |
| Maximum payload size | Bytes in a single PUBLISH | Publish rejected or connection closed |
| Subscriptions per client | Topic filters a client may hold | SUBACK returns a failure code |
| Topic depth | Number of levels separated by / |
Publish or subscribe rejected |
| Highest QoS | 0, 1 or 2 | Subscription granted at a lower QoS |
| Session expiry | How long the broker keeps an offline session | Queued messages lost after expiry |
Real plan limits as an example
Here is how ConnectMQ sets its limits by plan:
- Serverless (Free): up to 25 connections, QoS up to 1, messages up to 256 KB.
- Serverless (Paid): up to 1,000 connections, QoS 2, messages up to 1 MB, shared subscriptions.
- Dedicated, BYOC and Self Managed Enterprise: isolated deployments sized for your workload.
- Public test broker (broker.connectmq.com): 64 KB per message, 10 messages per second per client, 10 subscriptions per client, 8 topic levels, QoS 0 to 2 and session expiry up to 30 minutes.
How Brokers Signal That You Hit a Quota
This is where the protocol version matters a great deal.
MQTT 3.1.1: guessing from disconnects
MQTT 3.1.1 has only a handful of CONNACK return codes and no way for the broker to explain a disconnect. When a 3.1.1 client exceeds a limit, the broker usually just closes the TCP connection. The client sees a generic "connection lost" and reconnects, often hitting the same limit again. Diagnosing quota problems on 3.1.1 means correlating client logs with whatever the provider's console shows.
MQTT 5: explicit reason codes
MQTT 5 added reason codes to CONNACK, PUBACK, SUBACK and DISCONNECT, which makes quota problems visible to the client. The ones you will meet most often are defined in the OASIS MQTT 5.0 specification:
| Code | Name | Meaning in practice |
|---|---|---|
| 0x87 | Not authorized | Credentials or client ID do not allow this action |
| 0x8E | Session taken over | Another client connected with the same client ID |
| 0x95 | Packet too large | Payload exceeds the maximum packet size |
| 0x96 | Message rate too high | Publish rate exceeded |
| 0x97 | Quota exceeded | An implementation or plan quota was hit |
| 0x9F | Connection rate exceeded | Too many connection attempts |
ConnectMQ supports MQTT 5 reason codes, including 0x97 quota exceeded, so a client using MQTT 5 can log a precise cause instead of a vague disconnect. That alone is a strong reason to use MQTT 5 for new projects; see MQTT 5 features for the rest.
MQTT 5 brokers can also advertise limits up front in CONNACK properties such as Maximum Packet Size, Receive Maximum, Topic Alias Maximum and Maximum QoS. A well-written client reads them and adapts.
Designing Clients That Stay Inside Their Quotas
The best quota strategy is a client that never gets near the limit. These practices prevent most quota incidents.
Read the broker's limits at connect time
The Python example below connects with paho-mqtt 2.x over TLS, prints the limits the broker advertises and logs reason codes on disconnect.
import paho.mqtt.client as mqtt
LIMIT_PROPS = ("MaximumPacketSize", "ReceiveMaximum",
"TopicAliasMaximum", "MaximumQoS", "SharedSubscriptionAvailable")
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code.is_failure:
print("connect refused:", reason_code)
return
print("connected")
for name in LIMIT_PROPS:
value = getattr(properties, name, None)
if value is not None:
print(f" broker limit {name} = {value}")
def on_disconnect(client, userdata, flags, reason_code, properties):
print("disconnected:", reason_code)
if reason_code == "Quota exceeded":
print("plan quota hit; back off and alert an operator")
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id="YOUR_CLIENT_ID", protocol=mqtt.MQTTv5)
client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.tls_set()
client.reconnect_delay_set(min_delay=1, max_delay=120)
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.connect("broker.connectmq.com", 8883, keepalive=60)
client.loop_forever()
If you want to experiment without an account first, point the same script at the free public MQTT broker on port 1883 with a unique client ID and no credentials.
Rate-limit publishes on the client
Never rely on the broker to throttle you. A small token bucket keeps bursts under control, which matters most after a device reconnects and tries to flush a backlog.
const mqtt = require("mqtt");
const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
clientId: "YOUR_CLIENT_ID",
username: "YOUR_USERNAME",
password: "YOUR_PASSWORD",
protocolVersion: 5,
reconnectPeriod: 5000,
});
// Token bucket: at most RATE messages per second, burst up to BURST.
const RATE = 5;
const BURST = 10;
let tokens = BURST;
setInterval(() => { tokens = Math.min(BURST, tokens + RATE); }, 1000);
const queue = [];
function enqueue(topic, payload) { queue.push({ topic, payload }); }
setInterval(() => {
while (tokens >= 1 && queue.length > 0 && client.connected) {
const { topic, payload } = queue.shift();
client.publish(topic, payload, { qos: 1 });
tokens -= 1;
}
}, 100);
client.on("connect", () => console.log("connected"));
client.on("disconnect", (packet) => console.log("broker disconnect, reason", packet.reasonCode));
// Simulate a backlog flush after an outage.
for (let i = 0; i < 50; i++) enqueue("factory/line1/temp", JSON.stringify({ i, c: 20 + Math.random() }));
Back off with jitter on reconnect
When a site loses connectivity, hundreds of devices may reconnect within the same second. Without randomized backoff they hit the connection rate quota together, fail together and retry together. Add random jitter to every reconnect delay and cap the maximum delay at a minute or two.
Keep client IDs unique and stable
On managed brokers that bind client IDs to issued credentials, as ConnectMQ does, duplicates are a common trap. If you copy one set of credentials onto two devices, each connection kicks the other off, which MQTT 5 reports as 0x8E session taken over. The result looks like a flapping connection and quickly burns through connection-rate limits. Issue one credential set per device or service.
Batch small readings
Ten sensor values in one JSON message cost one publish instead of ten. Batching keeps message rates down and usually reduces bandwidth, provided the batch stays well under your plan's payload limit.
Use fewer, broader subscriptions
A single wildcard such as site1/+/telemetry is cheaper to manage than dozens of exact subscriptions, and it keeps you clear of per-client subscription caps.
A Quota Readiness Checklist
Before rollout, walk through this list for every client type:
- Count concurrent connections, including dashboards, scripts and integrations.
- Calculate peak publishes per second per client, not just the average.
- Measure the largest payload, including backlog flushes and error dumps.
- Confirm the QoS level each topic needs and that the plan supports it.
- Verify every device has its own client ID and credentials.
- Implement exponential backoff with jitter for reconnects.
- Log MQTT 5 reason codes and ship them somewhere you can search.
- Leave headroom: plan for roughly double your expected load so growth does not surprise you.
For the sizing math behind points 2 and 3, read estimating MQTT messages per second. If you are comparing entry-level options, our guide to the MQTT broker free tier shows how quotas differ between free plans, and the cloud MQTT broker pillar covers hosting choices more broadly.
Troubleshooting Quota Problems
- Connections drop every few seconds: check for duplicate client IDs before anything else.
- Large messages vanish: compare the payload size against the plan limit and the broker's Maximum Packet Size property.
- Subscriptions silently receive nothing: inspect the SUBACK reason codes; a failure code means the filter was not accepted.
- Everything fails after a site-wide outage: your reconnect logic lacks jitter and you are tripping connection-rate protection.
- Unexplained disconnects on MQTT 3.1.1: switch the client to MQTT 5 temporarily to get a reason code.
Get Started with a Managed MQTT Plan
ConnectMQ publishes its plan limits clearly and reports quota problems with MQTT 5 reason codes, so you can design to them from day one. Start on the free Serverless plan at app.connectmq.com with no credit card, then step up to paid Serverless, Dedicated or BYOC as your fleet grows. If you prefer someone else to run the infrastructure entirely, a fully managed MQTT service handles patching, TLS and capacity for you.
Frequently Asked Questions
What does MQTT reason code 0x97 mean?
0x97 is "Quota exceeded" in MQTT 5. The broker is telling the client that an implementation or plan limit was reached, so the client should back off rather than retry immediately.
Do dashboards and scripts count toward connection quotas?
Yes. Every MQTT client holding an open session counts as one connection, whether it is a sensor, a Node-RED flow or a browser tab.
How do I know the maximum message size my broker accepts?
Check the plan documentation and, on MQTT 5, read the Maximum Packet Size property in CONNACK. The ConnectMQ free Serverless plan allows 256 KB and the paid Serverless plan allows 1 MB.
Why does my device keep reconnecting in a loop?
The most common cause is two clients sharing one client ID, which makes the broker disconnect the older session each time. Give every device its own credentials and client ID.



