Managed MQTT Cloud

How to Scale an MQTT Broker: Connections, Throughput and Fan-Out

Scaling MQTT is about three numbers: connections, inbound messages and outbound fan-out. Learn how each grows, which scaling strategies fit, and which client habits matter most.

How to scale an MQTT broker illustration with many devices feeding a broker that fans messages out to multiple subscriber groups
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

Knowing how to scale an MQTT broker starts with knowing which kind of load is actually growing: connections, inbound messages or outbound fan-out. This guide explains each dimension, compares vertical and horizontal scaling, walks through the fan-out math you need for sizing, and shows the client-side habits that often matter more than the broker itself.

The Three Dimensions of MQTT Load

An MQTT broker does three different kinds of work, and they scale independently.

Connections. Each connected client holds a TCP socket, a TLS session if encrypted, a session state object and keepalive timers. Connection load is mostly about memory and file descriptors, and it grows with fleet size even when devices are quiet.

Inbound messages. Every PUBLISH from a client must be parsed, authorized, matched against subscriptions and acknowledged if QoS is 1 or 2. Inbound load grows with fleet size multiplied by publish frequency.

Outbound fan-out. For every inbound message, the broker delivers a copy to every matching subscriber. One sensor reading consumed by a dashboard, a database writer and an alerting service becomes three outbound messages. Fan-out is the dimension teams most often forget, and it is frequently the largest.

A fourth, quieter factor is session state: persistent sessions with queued QoS 1 messages for offline clients consume memory until those clients return or the session expires.

Fan-Out Math: Estimating Real Broker Load

You do not need a benchmark to reason about load; you need arithmetic. The basic formulas are:

  • Inbound rate = devices x messages per device per second
  • Outbound rate = sum over topics of (inbound rate on that topic x matching subscribers)
  • Total broker work is roughly inbound plus outbound, with extra cost for QoS 1 and 2 acknowledgements and for TLS

Here is a small calculator you can adapt to your own fleet. The numbers in it are an example, not a measurement.

# fanout.py - rough MQTT load estimate for capacity planning
fleet = [
    # (name, devices, msgs_per_device_per_min, subscribers_per_message, avg_payload_bytes)
    ("env sensors",  400, 2,  2, 180),
    ("machines",      60, 60, 3, 600),
    ("status",       460, 0.1, 1, 20),
]

total_in = total_out = total_bytes = 0.0
for name, devices, per_min, subs, size in fleet:
    inbound = devices * per_min / 60
    outbound = inbound * subs
    total_in += inbound
    total_out += outbound
    total_bytes += (inbound + outbound) * size
    print(f"{name:12s} in={inbound:7.1f}/s out={outbound:7.1f}/s")

print(f"\nTOTAL inbound  {total_in:8.1f} msg/s")
print(f"TOTAL outbound {total_out:8.1f} msg/s")
print(f"Approx traffic {total_bytes/1024:8.1f} KB/s (payload only, no protocol/TLS overhead)")

Run it with python fanout.py. Two lessons usually jump out. First, a handful of chatty machines can outweigh hundreds of slow sensors. Second, adding one more subscriber to a high-volume topic, such as a second analytics service, can raise outbound load more than adding hundreds of devices. For a deeper walk-through, read estimating MQTT messages per second.

Vertical vs Horizontal Scaling

There are two broad ways to give a broker more capacity.

Vertical scaling Horizontal scaling
How Bigger machine: more CPU, memory, network More broker nodes working together
Complexity Low; configuration mostly unchanged Higher; nodes must share routing and session state
Failure domain One node Several nodes, depending on design
Typical limit Largest machine available Coordination overhead between nodes
Good for Most small and medium fleets Very large fleets or strict redundancy goals

Vertical scaling is underrated. A single well-tuned broker process on adequate hardware handles a large amount of traffic, and the operational simplicity is valuable. Tuning usually involves raising file descriptor limits, sizing memory for sessions and in-flight messages, and offloading or optimizing TLS.

Horizontal scaling means several broker nodes behind a load balancer. The hard part is not adding nodes but keeping them consistent: a message published on node A must reach a subscriber connected to node B, and a client that reconnects to a different node expects to find its session. Different broker products solve this in different ways, with different trade-offs in latency and consistency.

A third pattern is partitioning: running separate, independent brokers for separate sites, tenants or product lines. It avoids cross-node coordination entirely, at the cost of not having one global topic space. For many multi-site and multi-customer deployments, partitioning is the simplest way to grow.

Scaling the Consumer Side with Shared Subscriptions

Backend consumers are often the first bottleneck. A single Python service subscribed to acme/# must process every message the fleet sends. When it falls behind, messages queue on the broker and memory grows.

MQTT 5 shared subscriptions fix this by letting several consumer instances split one subscription. Each message goes to one member of the group rather than to all of them. Shared subscriptions are available on the ConnectMQ Serverless (Paid) plan.

import os
import paho.mqtt.client as mqtt

GROUP = "writers"
FILTER = "acme/+/+/+/+/telemetry"

def on_connect(client, userdata, flags, reason_code, properties):
    print("connected:", reason_code)
    client.subscribe(f"$share/{GROUP}/{FILTER}", qos=1)

def on_message(client, userdata, msg):
    # Write to your database, queue or file here.
    print(os.getpid(), msg.topic, len(msg.payload), "bytes")

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.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 8883)
client.loop_forever()

Run one copy per consumer instance, each with its own credentials and client ID. Adding an instance spreads the load further without touching the devices.

Client-Side Habits That Scale

Many scaling problems are really client problems. These habits help on any broker:

  1. Publish on change, not on a timer. Report-by-exception cuts inbound load dramatically for slow-changing values.
  2. Batch readings. Send ten samples in one message instead of ten messages.
  3. Use QoS deliberately. QoS 0 for high-frequency telemetry where the next sample supersedes the last; QoS 1 for events and commands; QoS 2 only where duplicates are unacceptable. See MQTT QoS levels explained.
  4. Subscribe narrowly. A dashboard showing one site should not subscribe to #.
  5. Set sensible keepalives. Very short keepalives multiply PINGREQ traffic across a large fleet.
  6. Add jitter to reconnects and to periodic publishes. Thousands of devices publishing on the exact same second create needless spikes.
  7. Expire what you do not need. Session expiry and message expiry stop the broker from holding state for clients that will never return.
  8. Use topic aliases for long topics on constrained links. MQTT 5 topic aliases replace repeated long topic strings with a short integer.

When to Move to a Bigger Plan

On a managed service, scaling is mostly a plan decision. With ConnectMQ the ladder looks like this:

  • Serverless (Free): up to 25 connections, QoS up to 1, 256 KB messages. Prototypes and small pilots.
  • Serverless (Paid): up to 1,000 connections, QoS 2, 1 MB messages, shared subscriptions. Growing fleets on a shared cluster.
  • Dedicated: an isolated cluster so your workload does not share resources with other tenants.
  • BYOC: a broker running in your own cloud account and managed by ConnectMQ, useful when you want to choose and control the infrastructure.
  • Self Managed Enterprise: for organizations that need to operate the broker themselves.

Signals that you should move up include approaching the connection ceiling, needing shared subscriptions for backend consumers, or wanting isolation from other tenants' traffic. Talk to the team about expected connections and message rates so a Dedicated or Enterprise deployment is sized to your workload. If you are comparing models generally, the cloud MQTT broker guide covers each one, and MQTT broker high availability explains the redundancy questions to ask alongside capacity.

Scaling Pitfalls to Avoid

  • Sizing on averages. Plan for peaks such as shift changes, reconnect storms and backlog flushes.
  • Ignoring subscribers. Count outbound fan-out, not just devices.
  • One giant wildcard consumer. Split it with shared subscriptions before it becomes a bottleneck.
  • Large retained messages everywhere. Every new subscriber receives them immediately, which adds up on wide wildcards.
  • Load testing against production. Use a separate broker or plan for load tests so you do not hit your own quotas.

Scale Your MQTT Fleet with ConnectMQ

ConnectMQ lets you start small and move up the plan ladder as your connections and fan-out grow, without changing protocols or topic design. Create a free Serverless broker at app.connectmq.com, no credit card needed, and upgrade when your numbers say it is time. If you want a refresher on what an MQTT broker does before planning, start there.

Frequently Asked Questions

What usually limits MQTT broker scaling first?

It depends on the workload. Large, quiet fleets hit connection and memory limits first, while busy fleets with several consumers per topic hit outbound fan-out limits first.

Is horizontal scaling always better than vertical scaling?

No. Vertical scaling is simpler and is enough for many deployments. Horizontal scaling adds coordination overhead and is worth it when a single node cannot meet capacity or redundancy goals.

How do shared subscriptions help with scaling?

They let several consumer instances split one subscription so each message is processed once by one member of the group. That removes the single-consumer bottleneck without changing devices.

When should I move from Serverless to Dedicated?

Consider Dedicated when you need isolation from other tenants or expect load beyond what the shared Serverless plans provide. Share your expected connections and message rates so the deployment is sized correctly.

Related articles

BYOC MQTT Broker: Bring Your Own Cloud Explained

A BYOC MQTT broker runs in your cloud account but is operated by a provider. Learn how the model works, the responsibility split, and how to prepare your account for it.

7 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.