MQTT penetration testing is a structured way to find weaknesses in your own broker and clients before someone else does. This guide gives you a repeatable methodology, from scoping and reconnaissance to authentication, authorisation, TLS and resource-limit checks, and ends with a hardening checklist you can hand to the team. Everything here is meant for systems you own or have written permission to test.
Rules of Engagement Come First
Testing a broker you do not own is unauthorised access in most jurisdictions, regardless of whether it "was open anyway". Before you send a single packet:
- Get written authorisation from the system owner, naming hosts, ports, dates and allowed techniques.
- Define what is out of scope, for example production devices that actuate physical equipment, third-party brokers and public test brokers.
- Prefer a staging copy. A broker with the same configuration but no live equipment lets you test write access without risk.
- Agree on stop conditions. If a test causes instability, stop and report.
On a managed service, the provider's acceptable use policy applies too. Test your own tenant's configuration and client behaviour, not the provider's shared infrastructure, and never run load or fuzzing campaigns against a shared cluster or a public broker such as broker.connectmq.com. Its per-client limits exist to keep it usable for everyone.
The Methodology at a Glance
| Phase | Goal | Typical evidence |
|---|---|---|
| 1. Scoping | Know what you are allowed to test | Signed scope, asset list |
| 2. Reconnaissance | Map listeners, versions and endpoints | Port list, TLS details, broker banner |
| 3. Authentication | Verify that only valid identities connect | Results of anonymous, wrong and reused credential attempts |
| 4. Authorisation | Verify each identity is limited to its topics | Subscribe/publish matrix per role |
| 5. Transport security | Confirm encryption and certificate validation | TLS versions, cipher list, client verification behaviour |
| 6. Robustness | Check limits and malformed-input handling (staging) | Limit responses, broker stability |
| 7. Client review | Check devices and apps for secret handling | Firmware and config findings |
| 8. Reporting | Turn findings into fixes | Prioritised remediation list |
Phase 2: Reconnaissance of Your Broker
Start by listing every way a client can reach the broker. Teams often secure 8883 carefully and forget a WebSocket listener or an old plain listener.
# List MQTT-related ports on your own host
nmap -Pn -p 1883,8883,8083,8084,9001 your-broker.example.com
# Inspect the TLS endpoint
openssl s_client -connect your-broker.example.com:8883 -servername your-broker.example.com </dev/null
Record for each listener: protocol (TCP, TLS, WS, WSS), whether it is reachable from the internet, the certificate subject and expiry, and which MQTT versions it accepts. If the broker exposes $SYS topics, check what they reveal to an ordinary authenticated client. Version strings and client counts are useful to an attacker and rarely needed by devices.
Phase 3: Authentication Tests
Authentication tests answer one question: can anyone connect who should not? Run each test with an identifier that makes the attempt easy to find in logs.
- Anonymous connection. Connect with no username. Expected: refused with a "not authorised" reason.
- Wrong password. Expected: refused. Repeat a handful of times and confirm that repeated failures are detected or throttled.
- Valid credentials, wrong client ID. If your broker binds client IDs to credentials, a mismatch should be refused.
- Duplicate client ID. Connect twice with the same ID and observe session takeover. Make sure your devices handle it, and that an attacker with only a client ID cannot take over a session.
- Revoked credentials. Revoke a test identity and confirm it can no longer connect or reconnect.
A small Python script makes these checks repeatable:
import time
import paho.mqtt.client as mqtt
HOST, PORT = "your-broker.example.com", 8883
CASES = [
("anonymous", None, None, "pt-anon-01"),
("wrong-password", "YOUR_USERNAME", "not-the-password", "YOUR_CLIENT_ID"),
("valid", "YOUR_USERNAME", "YOUR_PASSWORD", "YOUR_CLIENT_ID"),
("valid-wrong-id", "YOUR_USERNAME", "YOUR_PASSWORD", "pt-other-id"),
]
def try_connect(name, user, pwd, cid):
result = {}
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=cid,
protocol=mqtt.MQTTv5)
client.tls_set() # verify server certificate with system CAs
if user:
client.username_pw_set(user, pwd)
def on_connect(c, userdata, flags, reason_code, properties):
result["rc"] = str(reason_code)
c.disconnect()
client.on_connect = on_connect
try:
client.connect(HOST, PORT, keepalive=10)
client.loop_start()
time.sleep(5) # wait for CONNACK
client.loop_stop()
except Exception as exc:
result["rc"] = f"exception: {exc}"
print(f"{name:16} -> {result.get('rc', 'no response')}")
for case in CASES:
try_connect(*case)
Only the valid case should report Success. Everything else should be refused with a clear reason code.
Phase 4: Authorisation Tests
Authentication proves who a client is; authorisation decides what it may do. Build a matrix of roles (sensor, gateway, dashboard, admin service) against topic patterns and test each cell with a real connection.
| Role | Publish site/+/telemetry |
Subscribe # |
Publish site/+/cmd |
Subscribe $SYS/# |
|---|---|---|---|---|
| Sensor | Allowed (own topic only) | Denied | Denied | Denied |
| Dashboard | Denied | Denied (scoped wildcard only) | Denied | Denied |
| Control service | Denied | Denied | Allowed | Denied |
Pay attention to how denials appear. In MQTT 5, a refused subscription returns a SUBACK reason code such as 0x87 (not authorised), and a refused QoS 1 publish returns a PUBACK with a reason code. In MQTT 3.1.1, a denied publish is usually dropped silently, so you must verify with a second, privileged subscriber that the message never arrived. On self-hosted brokers, the MQTT ACL guide explains how to express these rules. Where the broker does not offer per-topic rules, the equivalent control is separate brokers or tenants per trust zone.
Phase 5: Transport Security Tests
Check both sides of TLS:
- Server side: only modern protocol versions (TLS 1.2 and 1.3), a certificate from a trusted CA that matches the hostname, and no plain listener reachable from the internet.
- Client side: devices must reject a wrong certificate. Point a test device at a staging host with a self-signed or mismatched certificate and confirm the connection fails. A client that connects anyway is effectively unencrypted against an active attacker.
The MQTT TLS configuration article covers the correct client settings, and analysing MQTT traffic with Wireshark is a good way to prove that payloads are no longer visible on the wire.
Phase 6: Robustness and Limits (Staging Only)
Robustness testing checks how the broker and your clients behave with too much or malformed input. Run it only on a staging broker you control, never on shared or production infrastructure.
- Oversized payloads: publish a message larger than your configured maximum. Expect a refusal, not a crash.
- Rate limits: publish faster than your policy allows and confirm the broker throttles or disconnects. On ConnectMQ plans, exceeding a quota is signalled with MQTT 5 reason code 0x97 (quota exceeded), which your clients should handle gracefully.
- Connection floods: open many connections from one source and check that limits apply per client or per IP.
- Protocol fuzzing: tools that mutate MQTT packets can reveal parsing bugs. Keep these on an isolated test broker and report crashes to the broker vendor.
For context on designing these limits, see MQTT rate limiting and DoS protection.
Phase 7: Client and Device Review
Many real-world findings live on the device rather than the broker:
- Credentials hard-coded in firmware or committed to a repository.
- One shared password for every device in a fleet.
- Debug topics that publish configuration or secrets.
- Command topics that execute payloads without validation.
- TLS verification disabled "to make it work".
Treat every device as potentially extracted and inspected by an attacker. Each one should have unique credentials that can be revoked on their own.
Hardening Checklist From Your Findings
Convert findings into outcomes the team can verify:
- Every listener requires authentication; anonymous access exists only where it is intentional and documented.
- Only TLS listeners are reachable from the internet, with a valid certificate.
- Every device and service has unique, revocable credentials.
- Each identity can publish and subscribe only to the topics it needs.
- Clients reject invalid certificates.
- Message size, rate and connection limits are configured and clients handle refusals.
- Repeated failed logins are throttled or blocked.
- Broker software is patched on a schedule.
- Retained and debug topics contain no secrets.
- Retesting is scheduled after major changes.
Several items on this list are handled by the platform when you use a fully managed MQTT service. On ConnectMQ, private brokers require generated credentials, client IDs are bound to those credentials, TLS uses a Let's Encrypt certificate, tenants are isolated, and flood protection plus IP blocking after repeated failed logins are built in. Your test effort can then focus on client behaviour and topic design. The MQTT security best practices article is a good companion for the client-side items.
Test Against a Broker You Control
The safest way to practise this methodology is on a broker you own. Create a private ConnectMQ broker on the free Serverless plan at app.connectmq.com (no credit card), run the authentication and TLS checks against your own credentials, and keep load and fuzzing tests on a local staging broker. For quick, non-sensitive experiments you can still use the free public MQTT broker, within its limits.
Frequently Asked Questions
Can I penetration test a public MQTT broker?
Not without the operator's explicit permission. Public test brokers are shared services, and load or fuzzing tests degrade them for everyone. Test your own brokers or a local staging copy.
What tools are commonly used for MQTT security testing?
Network scanners for listener discovery, openssl s_client for TLS checks, mosquitto_pub and mosquitto_sub for quick tests, and scripted clients such as paho-mqtt for repeatable authentication and authorisation matrices.
How often should we retest our MQTT setup?
After every significant change to listeners, credentials, topic structure or firmware, and on a regular schedule otherwise. Automating the authentication and authorisation checks makes frequent retesting cheap.
What is the most common finding?
Shared or hard-coded credentials on devices and TLS verification disabled on clients are frequent findings, alongside listeners that accept anonymous connections.



