Guides

Secure Mosquitto: Passwords, ACLs and TLS

Secure a Mosquitto broker step by step: create a password file with mosquitto_passwd, restrict topics with an ACL file using %u and %c, and enable TLS on 8883.

Updated · 8 min read

A fresh Mosquitto 2.x install refuses anonymous remote clients, which is a good start — but to actually use it you need three layers: authentication (who are you?), authorisation (which topics may you touch?) and encryption (can anyone on the network read this?). In Mosquitto these are the password file, the ACL file and a TLS listener. This guide sets up all three.

If the broker is not installed yet, start with installing Mosquitto or running it in Docker. Paths below assume a Linux package install; in Docker, use /mosquitto/config/ instead of /etc/mosquitto/.

1. Create a password file with mosquitto_passwd

mosquitto_passwd stores usernames with salted password hashes (never plain text). Create the file with the first user, then add more:

Create users
# -c creates a NEW file and overwrites any existing one — first user only
sudo mosquitto_passwd -c /etc/mosquitto/passwd alice

# add or update users (prompts for the password)
sudo mosquitto_passwd /etc/mosquitto/passwd sensor-01

# non-interactive, e.g. in provisioning scripts
sudo mosquitto_passwd -b /etc/mosquitto/passwd bob 'S3cure-pass'

# delete a user
sudo mosquitto_passwd -D /etc/mosquitto/passwd bob

Avoid -b on shared machines: the password ends up in your shell history and the process list. Lock the file down so only the broker can read it:

bash
sudo chown mosquitto:mosquitto /etc/mosquitto/passwd
sudo chmod 0700 /etc/mosquitto/passwd

Now tell the broker to use it:

/etc/mosquitto/conf.d/secure.conf
listener 1883
allow_anonymous false
password_file /etc/mosquitto/passwd
Test it
sudo systemctl restart mosquitto

# should fail with "not authorised"
mosquitto_pub -h localhost -t test -m hi

# should succeed
mosquitto_pub -h localhost -u alice -P 'your-password' -t test -m hi

2. Restrict topics with an ACL file

A password file alone lets every authenticated user read and write every topic. An ACL file limits that. Once acl_file is set, anything not explicitly allowed is denied.

/etc/mosquitto/acl
# --- pattern rules apply to every authenticated client ---
# each device may read and write only below its own username
pattern readwrite devices/%u/#
# each client may read its own command topic, keyed by client ID
pattern read commands/%c

# --- user-specific rules ---
user alice
topic readwrite #

user dashboard
topic read devices/#
topic write commands/+

user sensor-01
topic write telemetry/sensor-01/#
DirectiveMeaning
user <name>Following topic lines apply to this username
topic [read|write|readwrite|deny] <filter>Grants (or with deny, blocks) access; wildcards + and # allowed. Omitting the access type means readwrite
pattern [access] <filter>Applies to all clients; %u is replaced by the username, %c by the client ID

Enable it next to the password file:

/etc/mosquitto/conf.d/secure.conf
listener 1883
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl

Two behaviours catch people out. First, a publish to a forbidden topic is silently dropped in MQTT 3.1.1 — the client sees no error (MQTT 5 clients get a reason code on QoS 1/2 PUBACK). Second, a forbidden subscription is refused in the SUBACK, which many client libraries do not surface. When "messages just do not arrive", check the ACL first and run the broker with log_type all while debugging. Use the topic matcher to check which topics a filter like devices/+/# really covers.

3. Encrypt traffic with TLS

Without TLS, usernames, passwords and payloads cross the network in plain text. The convention is MQTT over TLS on port 8883 (see MQTT ports). You need a certificate, its private key and — for self-signed setups — the CA certificate.

/etc/mosquitto/conf.d/tls.conf
# MQTT over TLS
listener 8883
certfile /etc/mosquitto/certs/server.crt
keyfile  /etc/mosquitto/certs/server.key
# cafile is only needed for self-signed / private CA chains or client certificates
# cafile /etc/mosquitto/certs/ca.crt

# Secure WebSockets for browser clients
listener 8884
protocol websockets
certfile /etc/mosquitto/certs/server.crt
keyfile  /etc/mosquitto/certs/server.key

Once TLS works, remove or firewall the plain listener 1883 (or bind it to localhost with listener 1883 127.0.0.1) so credentials cannot leak over it. To require client certificates (mutual TLS), add cafile and require_certificate true to the listener; adding use_identity_as_username true makes the certificate's CN the username for ACL purposes.

Test from a client:

bash
# public CA (e.g. Let's Encrypt): use the system trust store
mosquitto_sub -h mqtt.example.com -p 8883 --capath /etc/ssl/certs \
  -u alice -P 'your-password' -t 'devices/#' -v

# self-signed / private CA
mosquitto_sub -h mqtt.example.com -p 8883 --cafile ca.crt \
  -u alice -P 'your-password' -t 'devices/#' -v

The hostname in -h must match the certificate's CN/SAN, otherwise verification fails. More CLI options are in the mosquitto_pub/sub cheat sheet.

Using a Let's Encrypt certificate

A publicly trusted certificate means clients do not need a custom CA file. Get one with certbot for your broker hostname (port 80 must be reachable for the HTTP challenge), then point Mosquitto at the live files:

ini
listener 8883
certfile /etc/letsencrypt/live/mqtt.example.com/fullchain.pem
keyfile  /etc/letsencrypt/live/mqtt.example.com/privkey.pem
  • Use fullchain.pem, not cert.pem — clients need the intermediate certificate.
  • The mosquitto user must be able to read the key; by default /etc/letsencrypt is root-only. Many setups copy the files into /etc/mosquitto/certs/ with a certbot deploy hook and set ownership there.
  • Certificates renew every few months. Add systemctl reload mosquitto to the deploy hook so the broker picks up the new certificate.

Putting it together

/etc/mosquitto/conf.d/secure.conf
listener 1883 127.0.0.1

listener 8883
certfile /etc/mosquitto/certs/fullchain.pem
keyfile  /etc/mosquitto/certs/privkey.pem

listener 8884
protocol websockets
certfile /etc/mosquitto/certs/fullchain.pem
keyfile  /etc/mosquitto/certs/privkey.pem

allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl

Rather than hand-editing, you can generate this with the mosquitto.conf generator. For the bigger picture — client ID policies, rate limits, monitoring — read MQTT security best practices, and if clients start failing with "not authorised", the connection errors guide explains each code.

Frequently asked questions

How do I reload the Mosquitto password file without restarting?

Send the broker a SIGHUP, for example sudo systemctl reload mosquitto or kill -HUP with the broker PID. Mosquitto rereads the password file and ACL file on SIGHUP, so existing clients stay connected.

What does %u mean in a Mosquitto ACL file?

In a pattern line, %u is replaced with the connecting client username and %c with its client ID. pattern readwrite devices/%u/# lets every user access only the topics under their own name.

Can Mosquitto use a Let’s Encrypt certificate?

Yes. Point certfile at fullchain.pem and keyfile at privkey.pem, make sure the mosquitto user can read them, and reload the broker after every renewal. Clients then verify the server with the system CA store.