Key Takeaways
- IoT load testing means simulating many devices against the backend that receives their data, usually an MQTT broker plus the services behind it. The load is the number of open connections and the message rate, not requests per second.
- The behaviours that break IoT backends are specific: connection count, keepalive traffic, reconnect storms after an outage, retained messages and persistent sessions, and fan-out to subscribers.
- MQTT needs a plugin or extension in the main open-source tools: the xk6-mqtt extension for k6 (MQTT 3.1.1 only, experimental) or a community plugin for JMeter. Check what your platform can run before you plan the test.
- Test device-side behaviour (battery, memory, radio) on real hardware. A load test covers the broker and backend side.
An IoT load test connects a large number of simulated devices to your broker or ingestion endpoint, has them publish and subscribe the way real devices do, and measures connect time, delivery latency, errors and broker resource use as the number of devices and the message rate grow. Most devices speak MQTT, CoAP or plain HTTP, so the first step is to find out which protocols your fleet really uses and to test those.
What is IoT load testing, and what does it cover?
IoT load testing has two halves. The backend half is what a load test can do: connect thousands of simulated devices to a broker or gateway and watch the platform behind it. The device half is firmware, battery, memory and radio behaviour on real hardware, which a load generator cannot reproduce. Keep the two separate in your plan.
On the backend half, the questions are different from a web test:
- How many connections can stay open? Devices hold connections for hours or days. Each one costs the broker memory, file descriptors and keepalive handling, even when nothing is sent.
- What message rate does the ingestion path sustain? Count publishes per second at your real payload sizes, and what happens downstream (rules, queues, databases, dashboards).
- What happens after a mass disconnect? When a network, a broker node or a load balancer fails, many devices reconnect at the same moment.
- How does delivery behave at each quality of service level? Higher levels add acknowledgement traffic and state.
Which IoT protocols should a load test cover?
Test the protocols your devices speak. The table summarises what each one asks of a test, from the specifications read in October 2026.
| Protocol | What the specification says | What to test |
|---|---|---|
| MQTT 3.1.1 and 5.0 (OASIS) | Publish/subscribe with three QoS levels: 0 at most once, 1 at least once, 2 exactly once. A keep alive interval makes the server drop a client it has not heard from in one and a half times that period. Retained messages are not deleted when a session ends. | Connections, publish rate per QoS, keepalive, session state, retained messages, subscriber fan-out |
| CoAP (RFC 7252) | A web-style protocol for constrained devices over UDP “with optional reliability”. Confirmable messages are acknowledged and retransmitted; the defaults include an ACK_TIMEOUT of 2 seconds and MAX_RETRANSMIT of 4. | Request rate, retransmissions, behaviour under packet loss |
| LwM2M (OMA SpecWorks) | A protocol for remote monitoring, configuration and control of connected devices. | Device registration and management traffic at fleet scale |
| AMQP 1.0 (OASIS) | An open protocol for business messaging, defined as a binary wire-level protocol for reliable exchange of messages between two parties. | Broker throughput and acknowledgement behaviour, more often between backend services than from devices |
| HTTP/HTTPS | Request/response, no persistent session by itself. | The usual web load test, for device APIs and firmware downloads |
MQTT 5.0 adds a session expiry interval, where 0 or absent means the session ends when the connection closes, and shared subscriptions, written $share/{ShareName}/{filter}, which let several consumers split a stream. Both change what a realistic test looks like. I have not tested CoAP, LwM2M or AMQP load tools for this post, so the sections below use MQTT, the most common case, for the concrete examples.
How do I load test an MQTT broker?
Decide four numbers first: how many devices connect, how often each publishes, how large each payload is, and which QoS level each uses. Take them from your fleet or your plan, not from a vendor’s marketing page. Then script each simulated device as one client that connects, subscribes if devices receive commands, publishes on a timer and stays connected for the length of the test.
The extension route in k6 is xk6-mqtt. Its README calls it an experimental extension that is “not officially supported yet”, and says its MQTT library supports MQTT 3.1.1 and not MQTT 5 (github.com/grafana/xk6-mqtt, October 2026). You need a k6 binary that includes the extension, built with xk6 or downloaded from the extension’s releases page. I downloaded the v0.3.4 release (2026-10-22) and ran this script against a throwaway local Eclipse Mosquitto 2 broker in Docker:
import { Client } from 'k6/x/mqtt';
import { Trend, Counter } from 'k6/metrics';
const BROKER = __ENV.MQTT_BROKER_ADDRESS || 'mqtt://127.0.0.1:18830';
const connectTime = new Trend('mqtt_connect_time', true);
const deliveryTime = new Trend('mqtt_publish_to_delivery', true);
const published = new Counter('mqtt_published');
const delivered = new Counter('mqtt_delivered');
export const options = {
scenarios: {
devices: { executor: 'per-vu-iterations', vus: 50, iterations: 1, maxDuration: '40s' },
},
thresholds: {
mqtt_connect_time: ['p(95)<500'],
mqtt_publish_to_delivery: ['p(95)<200'],
},
};
export default function () {
const client = new Client({ client_id: `device-${__VU}` });
const topic = `telemetry/${__VU}`;
let sent = 0;
const started = Date.now();
client.on('connect', () => {
connectTime.add(Date.now() - started);
client.subscribe(topic, { qos: 1 });
const id = setInterval(() => {
client.publish(topic, String(Date.now()), { qos: 1 });
published.add(1);
if (++sent === 10) {
clearInterval(id);
setTimeout(() => client.end(), 500); // let the last delivery arrive
}
}, 1000);
});
client.on('message', (_topic, payload) => {
const sentAt = Number(String.fromCharCode.apply(null, new Uint8Array(payload)));
deliveryTime.add(Date.now() - sentAt);
delivered.add(1);
});
client.connect(BROKER, { keepalive: 30, clean_session: true });
}
Fifty simulated devices each published ten QoS 1 messages one second apart and received their own message back. The run completed all 500 publishes and 500 deliveries, with a connect time p95 of 11 ms and a publish-to-delivery p95 of 12 ms. Those numbers describe a laptop talking to a local broker: they show the script works, not how any real broker performs. Per-VU iterations: 1 is deliberate. With xk6-mqtt each iteration blocks until the connection ends, so a normal looping scenario would reconnect every device again and again and turn the test into a reconnect storm you did not ask for.
For JMeter, the community MQTT plugin from EMQX (maintained by XMeter, Apache 2.0 license, last repository update May 2025 at the time of reading) adds Connect, Pub, Sub and DisConnect samplers. Its README describes the Connect sampler as usable to simulate large numbers of background connections that send only heartbeats, and offers MQTT versions 3.1 and 3.1.1 (github.com/emqx/mqtt-jmeter). EMQX also publishes emqtt-bench, a command line MQTT benchmark tool with connect, publish and subscribe modes, a connection rate option and MQTT 5.0 as the default version (github.com/emqx/emqtt-bench). It is built by a broker vendor, so use it as one more load source and check the numbers against your own measurements.
What breaks IoT backends under load?
These are the patterns to build into the scenario, each from the behaviour the specifications describe:
- Keepalive traffic. In MQTT 3.1.1, a server disconnects a client that sends nothing within one and a half times its keep alive interval, so idle devices still cost a stream of ping packets. A fleet with short intervals puts steady load on the broker even when no data flows. Test with your real interval.
- Reconnect storms. Stop a broker node or the load balancer during a run and watch how many devices reconnect at once, how long connects take, and whether the system recovers on its own. Devices that retry on a fixed interval make it worse; the usual remedy is backoff with random jitter in the device firmware. A test that never disconnects anything misses this failure.
- Session state. With clean sessions off, or an MQTT 5.0 session expiry above zero, the broker stores subscriptions and queued messages for devices that are offline. Test a population of offline devices coming back after an hour, and measure queue size and delivery rate, not only connect time.
- Retained messages. They persist after a session ends, so a topic design with one retained message per device grows storage for the life of the fleet. Include them in the dataset, then test a mass subscribe that receives all of them.
- Fan-out. One publish delivered to many subscribers multiplies work. Model your real ratio of publishers to subscribers, and consider shared subscriptions if backend consumers split a stream.
- TLS. Each new TLS connection costs a handshake, so the reconnect storm is more expensive with encryption on, which is how production should run. Test with TLS, not plain TCP.
- The load generator’s own limits. Holding tens of thousands of connections from one machine runs into file descriptor and port limits before the broker is stressed. Spread the devices over several generators and watch the generator’s CPU and memory so you do not measure your own test rig. The network jitter post covers keeping generator-side effects out of the results.
How do I simulate realistic device behaviour?
Real fleets are not uniform. Give each device group its own message interval, payload size and QoS, stagger start times so the fleet does not publish in the same second, and add a share of devices that connect, send a burst and sleep. Use percentiles, not averages, when you report delivery latency (the percentiles article explains why). For per-device identities and credentials, feed client IDs and usernames from a data file, as in data-driven load testing scripts. Edge gateways that batch and forward device data change the traffic shape the backend sees, so test the gateway as its own tier; see edge computing and load testing for that part.
Can I use LoadFocus for an IoT load test?
LoadFocus runs JMeter and k6 scripts from 25 cloud regions (loadfocus.com/index.md, October 2026). Its JMeter page says a test plan’s CSV data and plugins “come along” and lists MQTT among the protocols JMeter covers (loadfocus.com/jmeter-load-testing, October 2026). The pages do not name specific MQTT plugins, say how many long-lived connections a generator holds, or document MQTT on the k6 side, where an extension needs a custom k6 binary. So an MQTT test on LoadFocus is a question for support before you plan it: ask which plugin or extension versions the generators carry, the connection limits per plan and the maximum test duration. For the HTTP side of an IoT platform (device APIs, firmware downloads, dashboards), the load testing page describes HTTP tests with real-time response time percentiles.
Frequently Asked Questions
What is IoT load testing?
It is load testing the backend that receives data from connected devices: simulated devices open connections, publish and subscribe over protocols such as MQTT, and the test measures connect time, delivery latency, errors and broker resource use as the device count and message rate grow.
How do I load test an MQTT broker?
Script each simulated device as an MQTT client that connects, publishes on a timer at your real QoS level and stays connected. In k6 that takes the xk6-mqtt extension; in JMeter, an MQTT plugin. Measure connect time and publish-to-delivery latency as percentiles, and include a deliberate disconnect to test reconnection.
Does k6 support MQTT?
Through an extension. The k6 extensions page lists xk6-mqtt under official extensions, while its own README calls it experimental and says it supports MQTT 3.1.1, not 5.0. You need a k6 binary built with it.
What is a reconnect storm?
It is many devices reconnecting at once after an outage, which loads the broker and load balancer with connection handshakes at the moment they are least able to cope. Test it by dropping a broker node or the balancer mid-run and measuring recovery time.
How many devices can one load generator simulate?
It depends on the generator’s file descriptor and port limits, memory and CPU, and on how chatty the devices are. I have no general number. Measure on your own setup by raising the connection count until the generator itself becomes the bottleneck, then distribute across generators.
Should I test with MQTT QoS 2?
If your devices use it. The specification calls QoS 2 the highest level, for when neither loss nor duplication is acceptable, and says it carries increased overhead, so a fleet that uses it needs its own measurements.
Sources
- MQTT Version 3.1.1, OASIS Standard (QoS levels, keep alive, retained messages; read 2026-10-23)
- MQTT Version 5.0, OASIS Standard (session expiry interval, shared subscriptions; read 2026-10-23)
- RFC 7252, The Constrained Application Protocol (CoAP) (UDP, confirmable messages, transmission parameters; read 2026-10-23)
- OMA SpecWorks, Lightweight M2M (read 2026-10-23)
- AMQP 1.0 Part 0: Overview, OASIS Standard (read 2026-10-23)
- xk6-mqtt repository and API docs and the k6 extensions page (grafana.com/docs/k6/latest/extensions/explore) (read 2026-10-23)
- EMQX mqtt-jmeter and emqtt-bench READMEs (read 2026-10-23)
- LoadFocus index.md and JMeter load testing page (loadfocus.com, read 2026-10-23)
- Local test: k6 v2.3.0 with xk6-mqtt v0.3.4 against Eclipse Mosquitto 2 in Docker, 2026-10-23