MQTT was designed for constrained networks, not hostile ones. Out of the box, many brokers accept anonymous clients on port 1883 and send everything in clear text. None of that is a flaw in the protocol — MQTT has all the hooks you need — but security is something you have to switch on. This guide walks through each layer and ends with a checklist you can use for reviews.
What you are protecting against
- Eavesdropping — reading credentials and payloads on the network.
- Impersonation — a rogue client connecting as one of your devices or services.
- Unauthorized publishing — someone sending
unlocktohome/door/cmd. - Data leakage — a client subscribing to
#and reading everything. - Denial of service — floods of connections or messages exhausting the broker.
1. Encrypt everything with TLS
TLS protects credentials and payloads in transit and lets clients verify they are talking to the real broker. Use port 8883 for MQTT over TLS and wss:// for browsers; disable or firewall the plain 1883 listener anywhere outside a trusted local network. Details in MQTT ports explained and MQTT over WebSockets.
- Require TLS 1.2 or newer.
- Always verify the server certificate on clients. Options such as
--insecure,setInsecure()orrejectUnauthorized: falseare for local debugging only. - Plan certificate renewal — an expired certificate takes every device offline at once.
mosquitto_sub -h broker.example.com -p 8883 --cafile ca.crt \
-u sensor-01 -P 'secret' -t 'devices/sensor-01/#' -v2. Authenticate every client
Turn off anonymous access. Then choose an authentication method that fits each kind of client:
| Method | Good for | Watch out for |
|---|---|---|
| Username and password | Most setups; supported by every client library | Only safe over TLS; give each device its own credentials |
| Client certificates (mutual TLS) | Device fleets with a provisioning process | Needs a CA, revocation and certificate rotation |
| Tokens (for example JWT in the password field) | Browser and mobile apps, short-lived access | Broker support varies; keep lifetimes short |
| MQTT 5 enhanced authentication | Challenge/response schemes such as SCRAM | Limited support in brokers and client libraries |
Never share one login across a fleet: if a single device is compromised, you want to revoke one credential, not re-flash every device. Store passwords hashed on the broker — Mosquitto users can follow the Mosquitto authentication guide, and the mosquitto.conf generator builds a secure configuration with TLS and password files.
3. Authorize topics with ACLs
Authentication answers who are you; authorization answers what may you do. Without ACLs, any authenticated client can read and write every topic. Apply least privilege: each client gets read or write access only to the topics it needs.
# backend service: read all telemetry, send commands
user backend
topic read devices/+/telemetry
topic write devices/+/cmd
# every device: only its own topics (%u = username)
pattern write devices/%u/telemetry
pattern read devices/%u/cmdPattern rules that substitute the username or client ID scale far better than one rule per device. Verify your filters with the topic matcher; MQTT wildcards are covered in topics and wildcards.
4. Control client IDs
A client that connects with an existing client ID kicks the original connection off the broker. An attacker who knows your IDs can use that to disconnect devices, and an accidental duplicate causes endless reconnect loops. Bind client IDs to credentials where your broker allows it (for example, require the client ID to equal the username or certificate common name), and avoid predictable IDs on shared brokers. The client ID generator helps create unique ones.
5. Design topics with security in mind
- Put the device or tenant ID in a fixed position so ACL patterns can match it.
- Separate telemetry (device writes) from commands (device reads) into different subtrees.
- Keep secrets and personal data out of topic names — topics show up in logs and monitoring tools.
- Be careful with retained messages on command topics: a retained
unlockfires again on reconnect.
6. Encrypt or sign sensitive payloads
TLS protects each hop, but the broker sees payloads in clear text. If the broker operator or other services on it should not read the data, encrypt payloads end to end (for example AES-GCM with keys managed outside MQTT), or at least sign commands so devices can reject forged ones. Validate every incoming payload on the device: enforce size limits, check types and ignore unknown commands.
7. Set limits and rate limits
Cap maximum packet size, inflight and queued messages per client, connection rate and the number of subscriptions. MQTT 5 lets the broker announce limits such as maximum packet size and receive maximum to clients. Rate limits stop a buggy device in a publish loop from taking down everyone else — use the packet size calculator to set realistic size caps.
8. Protect credentials on devices and in apps
Device credentials end up in flash memory, and browser credentials end up in JavaScript bundles anyone can read. Assume they can be extracted: give each client the narrowest ACL possible, provision credentials per device at manufacturing or first boot instead of baking one secret into the firmware, and use flash encryption or a secure element where the hardware supports it. For web and mobile apps, issue short-lived credentials from your backend instead of shipping a long-lived password.
9. Monitor and log
- Log connects, disconnects and authentication failures, and alert on spikes.
- Watch for clients subscribing to
#or$SYS/#unexpectedly. - Track connection counts and message rates per client to spot compromised or misbehaving devices.
- Keep the broker and client libraries patched.
MQTT security checklist
| Area | Check |
|---|---|
| Transport | TLS on 8883 / wss; plain 1883 disabled or firewalled; clients verify the server certificate |
| Certificates | Renewal automated or scheduled; expiry monitored |
| Authentication | Anonymous access off; unique credentials per device or service; passwords hashed |
| Authorization | ACLs enforce least privilege; no client can subscribe to # without a reason |
| Client IDs | Unique, ideally bound to the username or certificate |
| Topics | Telemetry and commands separated; no secrets in topic names; no retained commands |
| Payloads | Validated on receipt; sensitive data encrypted or signed end to end |
| Limits | Max packet size, queue sizes, connection and message rate limits configured |
| Monitoring | Auth failures and unusual traffic logged and alerted; software patched |
| Environments | No production data on public brokers; separate credentials for dev and prod |
When a locked-down client cannot connect, the CONNACK reason code tells you whether it was credentials or authorization — look it up in the MQTT reason code reference.
Frequently asked questions
Is MQTT secure by default?
No. Plain MQTT on port 1883 sends credentials and payloads unencrypted, and many brokers allow anonymous connections out of the box. MQTT becomes secure when you add TLS, require authentication and restrict each client to the topics it needs with ACLs.
Should I use username/password or client certificates for MQTT?
Both are fine over TLS. Username and password is simpler to manage and supported everywhere. Client certificates (mutual TLS) avoid shared secrets and suit large device fleets with a provisioning process. Many deployments use certificates for devices and passwords or tokens for backend services.
Is it safe to use a public MQTT broker?
Only for testing with dummy data. On a public broker anyone can subscribe to your topics and publish to them, there is no access control and no guarantee of availability. Real devices and real data belong on a private broker with authentication and TLS.