Before an MQTT broker carries real devices, run through this MQTT broker test checklist: 25 concrete checks, each with a command and the expected result. It covers connectivity, TLS, authentication, ACLs, message semantics, resilience and capacity — the areas where production incidents actually start.
All examples use the Mosquitto command-line clients (mosquitto_pub, mosquitto_sub) and broker.connectmq.com. Replace the host, ports and credentials with your own broker. Unless noted, the clients speak MQTT 3.1.1; add -V mqttv5 to test MQTT 5 behaviour.
export HOST=broker.connectmq.com
export T=testmqtt/checklist-$RANDOM # unique topic prefix for this run
export AUTH="-u $MQTT_USER -P $MQTT_PASS"
export TLS="-p 8883 --capath /etc/ssl/certs"Connectivity (checks 1–5)
1. DNS resolves to the expected address. dig +short $HOST returns the IPs you expect, from inside every network your clients use (office, cloud VPC, cellular APN).
2. Every listener port is reachable. Expect succeeded (or open) for each port you intend to expose, and a failure for the ones you do not:
for p in 1883 8883 8083 8084; do nc -zv -w 3 $HOST $p; done3. A client gets a CONNACK. mosquitto_pub -h $HOST -t $T/ping -m hi -d prints Client … received CONNACK (0). Anything else, or a hang, means a firewall, proxy or listener problem.
4. The WebSocket endpoint upgrades. Browsers need port 8084 with path /mqtt. The handshake must answer HTTP/1.1 101 Switching Protocols:
curl -si --http1.1 -m 5 https://$HOST:8084/mqtt \
-H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Protocol: mqtt" \
-H "Sec-WebSocket-Key: $(openssl rand -base64 16)" | head -1Then connect from the online MQTT client to confirm a real browser works too.
5. Connect time is within budget. time mosquitto_pub -h $HOST $TLS $AUTH -t $T/ping -m hi over TLS from your devices' region. Decide on a budget (for example 1–2 seconds on cellular) and fail the check above it.
TLS and authentication (checks 6–11)
6. The certificate chain and hostname verify. Expect Verify return code: 0 (ok) and an expiry date months away:
openssl s_client -connect $HOST:8883 -servername $HOST -verify_return_error </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -enddateA failure here is what devices later report as certificate verify failed. Testing an MQTT TLS connection covers each variant.
7. Plaintext is disabled where it should be. If production clients must use TLS, port 1883 on your production broker should refuse connections (check 2 should fail for 1883).
8. Anonymous clients are rejected. Without credentials, expect Connection error: Connection Refused: not authorised.
mosquitto_pub -h $HOST $TLS -t $T/anon -m x9. Wrong passwords are rejected. With a bad password, expect Connection Refused: bad user name or password. (MQTT 5: reason code 0x86). Look up any other code with the MQTT reason codes tool.
mosquitto_pub -h $HOST $TLS -u "$MQTT_USER" -P wrong-password -t $T/auth -m x10. ACLs block foreign topics. Log in as a device user and publish outside its namespace. Over MQTT 3.1.1 the broker silently drops the message, so verify with a privileged subscriber that nothing arrives. Over MQTT 5 at QoS 1 the PUBACK carries the refusal — the debug output shows RC:135 (0x87 Not authorized):
mosquitto_pub -h $HOST $TLS $AUTH -V mqttv5 -q 1 -d -t other-tenant/secret -m x11. Device users cannot subscribe to #. mosquitto_sub -h $HOST $TLS $AUTH -t '#' -C 1 -W 5 should print All subscription requests were denied. See testing MQTT ACL permissions for a full ACL matrix test.
Messaging semantics (checks 12–18)
12. Publish/subscribe round trip works. Subscribe, publish a unique token, receive it within a timeout. The one-minute smoke test script does exactly this with a pass/fail exit code.
13. QoS 1 is acknowledged. mosquitto_pub -h $HOST -q 1 -d -t $T/qos -m x shows received PUBACK. With -q 2, expect PUBREC and PUBCOMP.
14. Retained messages are stored and cleared.
mosquitto_pub -h $HOST -t $T/retained -m on -r -q 1
mosquitto_sub -h $HOST -t $T/retained -C 1 -W 5 -v # prints the retained value
mosquitto_pub -h $HOST -t $T/retained -r -n # empty retained payload clears it
mosquitto_sub -h $HOST -t $T/retained -C 1 -W 5 -v # times out: nothing retained15. Last Will is published on an unclean disconnect.
mosquitto_sub -h $HOST -t $T/status -v &
mosquitto_sub -h $HOST -i lwt-check -k 5 -t $T/none \
--will-topic $T/status --will-payload offline &
sleep 2; kill -9 $! # simulated crashThe first subscriber prints …/status offline. A clean DISCONNECT must not trigger it.
16. Persistent sessions queue offline messages. Connect with a fixed client ID and -c (clean session off), stop it, publish at QoS 1, reconnect with the same command — the queued message arrives:
mosquitto_sub -h $HOST -i queue-check -c -q 1 -t $T/queue -W 3 # creates the session
mosquitto_pub -h $HOST -q 1 -t $T/queue -m while-offline
mosquitto_sub -h $HOST -i queue-check -c -q 1 -t $T/queue -C 1 -W 517. Duplicate client IDs behave as expected. Start two clients with the same -i; the broker disconnects the first. Make sure every device generates a unique ID — the client ID generator helps — or you will see endless reconnect loops.
18. The maximum message size is known. Publish a payload just above your largest real message and confirm the broker's behaviour. Testing large MQTT payloads has a size-sweep script.
Resilience (checks 19–22)
19. Clients reconnect after a broker restart. On staging, restart the broker (docker restart mosquitto or systemctl restart mosquitto) and confirm that every client type reconnects, resubscribes and resumes publishing without manual action.
20. Dead connections are detected. Silently drop traffic to the broker (sudo iptables -A OUTPUT -p tcp --dport 8883 -j DROP) and verify that the client notices within about 1.5 × its keep-alive interval, then remove the rule. Chaos testing MQTT shows how to automate this with tc netem and Toxiproxy.
21. Reconnects use backoff with jitter. After a restart, connection attempts should spread out over seconds instead of arriving in one spike. Check client logs or the broker's connection rate graph.
22. Failover works, if you run a cluster. Stop one node and confirm clients move to another, sessions survive as designed and no retained state is lost.
Capacity and operations (checks 23–25)
23. The broker handles 2× expected peak. Run a load test with your real payload size, QoS and topic layout — see MQTT broker load testing — and record p99 latency and error rate.
24. Metrics are visible. Connected clients, message rates and dropped messages appear on a dashboard. On Mosquitto (where permitted): mosquitto_sub -h $HOST $AUTH -t '$SYS/broker/clients/connected' -C 1 -v.
25. Alerts actually fire. Trigger one on purpose: stop a test client that should always be online, or point a check at a certificate close to expiry, and confirm the alert reaches a human.
Turning the checklist into a script
| Checks | Manual time | How to automate |
|---|---|---|
| 1–6, 8–9, 12–16 | Minutes | Bash script with mosquitto_pub/mosquitto_sub, exit code per check |
| 10–11, 17–18 | Minutes | Same script with dedicated test users |
| 19–22 | Hours | Staging job with scripted restarts and network faults |
| 23–25 | Half a day | Scheduled load test plus monitoring rules |
Start by scripting the fast checks and running them in CI and after every broker change; keep the slow ones on a release checklist.
Run checks 3, 12 and 14 in your browser
A broker that passes these 25 checks has proven the things that matter on day one: clients can reach it securely, only the right clients get in, messages behave as designed, and failures heal on their own. Keep the commands in your repository and rerun them whenever the broker, its configuration or its certificates change.
Frequently asked questions
How long does it take to run an MQTT broker test checklist?
The connectivity, security and messaging checks take under an hour by hand and a few seconds once scripted. Resilience and load checks need a staging environment and usually half a day the first time.
Which MQTT checks matter most before going live?
TLS with a valid certificate, rejected anonymous and wrong-password logins, ACLs that block foreign topics, a working Last Will and client reconnect after a broker restart. These catch the failures that hurt most in production.
Can I run these checks against a public test broker?
Connectivity and messaging checks, yes. Authentication, ACL, restart and load checks need a broker you control, because a shared sandbox has its own open configuration and must not be stressed.

