Install the Mosquitto MQTT Broker
Install and secure Mosquitto MQTT broker with password auth, TLS on port 8883, ACL topic control, and a clean mosquitto.conf on Debian, Ubuntu, Fedora, and Arch.
Before you start
- ▸A Linux server with sudo or root access
- ▸openssl installed for certificate generation
- ▸Basic familiarity with systemd service management
- ▸Ports 1883 and 8883 available on the host
Mosquitto is a lightweight, open-source MQTT broker widely used for IoT projects, home automation, and sensor networks. This guide walks through installing Mosquitto, locking it down with password authentication and TLS, and controlling access with ACLs. By the end you will have a production-ready broker that rejects anonymous connections and encrypts all traffic.
Installation
Debian / Ubuntu
The mosquitto package in Ubuntu 22.04+ and Debian 12 is recent enough for production use. Add the official Mosquitto PPA on Ubuntu if you need the absolute latest.
sudo apt update
sudo apt install -y mosquitto mosquitto-clients
Fedora / RHEL / Rocky Linux
sudo dnf install -y mosquitto
On RHEL 8/9 and Rocky, enable EPEL first: sudo dnf install -y epel-release.
Arch Linux
sudo pacman -S mosquitto
Enable and Start the Service
sudo systemctl enable --now mosquitto
Verify it is running:
systemctl status mosquitto
Output will include Active: active (running). By default Mosquitto listens on port 1883 with no authentication — fix that next.
Core Configuration: mosquitto.conf
The main config file lives at /etc/mosquitto/mosquitto.conf. On Debian/Ubuntu, drop-in files are loaded from /etc/mosquitto/conf.d/. Keep the base file minimal and put your changes in a named drop-in, e.g. /etc/mosquitto/conf.d/local.conf. On Fedora/Arch the single file at /etc/mosquitto/mosquitto.conf is the standard entry point.
A commented skeleton for reference — we will build on this below:
cat /etc/mosquitto/mosquitto.conf
Password Authentication
Mosquitto uses its own password file format managed by mosquitto_passwd. Never edit the file by hand — the tool hashes passwords with bcrypt.
Create the password file
# Create the file and add the first user (-c creates, omit -c for subsequent users)
sudo mosquitto_passwd -c /etc/mosquitto/passwd mqttuser
You will be prompted to enter and confirm a password. Add more users without -c (which would overwrite the file):
sudo mosquitto_passwd /etc/mosquitto/passwd sensornode1
Enable authentication in config
Create or edit /etc/mosquitto/conf.d/local.conf:
sudo tee /etc/mosquitto/conf.d/local.conf <<'EOF'
listener 1883 0.0.0.0
allow_anonymous false
password_file /etc/mosquitto/passwd
EOF
Reload Mosquitto:
sudo systemctl reload mosquitto
Test that anonymous connections are now rejected:
mosquitto_sub -h localhost -t test/# -v
You should see Connection Refused: not authorised. A credentialed test:
mosquitto_sub -h localhost -t test/# -u mqttuser -P yourpassword -v &
mosquitto_pub -h localhost -t test/hello -m "world" -u mqttuser -P yourpassword
TLS Encryption
Plain MQTT on port 1883 sends credentials in cleartext. For anything beyond a trusted LAN, enable TLS on port 8883. You can use a certificate from Let's Encrypt or a self-signed CA. Below uses a self-signed CA suitable for internal infrastructure.
Generate a CA and server certificate
mkdir -p ~/mqtt-certs && cd ~/mqtt-certs
# CA key and certificate
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
-subj "/CN=MQTT-CA"
# Server key and CSR
openssl genrsa -out server.key 4096
openssl req -new -key server.key -out server.csr \
-subj "/CN=$(hostname -f)"
# Sign the server cert with the CA
openssl x509 -req -days 3650 -in server.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt
Install certificates
sudo mkdir -p /etc/mosquitto/certs
sudo cp ca.crt server.crt server.key /etc/mosquitto/certs/
sudo chown -R mosquitto:mosquitto /etc/mosquitto/certs
sudo chmod 640 /etc/mosquitto/certs/server.key
Add the TLS listener
Append to /etc/mosquitto/conf.d/local.conf:
sudo tee -a /etc/mosquitto/conf.d/local.conf <<'EOF'
listener 8883 0.0.0.0
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
tls_version tlsv1.2
EOF
Reload and verify both ports are open:
sudo systemctl reload mosquitto
ss -tlnp | grep mosquitto
Test TLS connectivity (copy ca.crt to the client first):
mosquitto_pub --cafile ~/mqtt-certs/ca.crt \
-h localhost -p 8883 \
-t test/tls -m "encrypted" \
-u mqttuser -P yourpassword
Access Control Lists (ACL)
ACLs restrict which users can publish or subscribe to which topics. Without an ACL file, any authenticated user can read and write everything — usually too permissive.
Create the ACL file
sudo tee /etc/mosquitto/acl <<'EOF'
# Global read-only topics anyone authenticated can subscribe to
topic read $SYS/#
# Per-user rules
user mqttuser
topic readwrite #
user sensornode1
topic write sensors/node1/#
topic read commands/node1/#
EOF
ACL syntax: topic [read|write|readwrite] <pattern>. The wildcard # matches any subtree; + matches one level. Rules are evaluated top-to-bottom per user; the first match wins.
Reference the ACL file in config
echo 'acl_file /etc/mosquitto/acl' | sudo tee -a /etc/mosquitto/conf.d/local.conf
sudo systemctl reload mosquitto
Topic Structure Best Practices
A consistent topic hierarchy makes ACLs maintainable and clients predictable.
- Start with a namespace: Use your organisation or project name as the root —
acme/— to avoid collisions when bridging brokers. - Encode location/device type/device ID: e.g.
acme/factory1/temperature/sensor42. - Use lowercase, hyphens, no spaces: Avoid special characters that may need URI encoding in some clients.
- Separate command and telemetry trees: e.g.
acme/+/sensors/#for data inbound,acme/+/commands/#for outbound control. This maps cleanly to ACL rules. - Reserve
$SYS/#for broker statistics: Never publish to$SYSfrom application code; it is a Mosquitto-internal namespace. - Avoid deep hierarchies past 6-7 levels: It complicates wildcard subscriptions and ACL management without adding value.
Firewall
Open only the ports you expose externally. Keep port 1883 off the internet; expose 8883 only if clients are remote.
ufw (Ubuntu / Debian)
sudo ufw allow 8883/tcp comment 'MQTT TLS'
sudo ufw reload
firewalld (Fedora / Rocky)
sudo firewall-cmd --permanent --add-port=8883/tcp
sudo firewall-cmd --reload
Verification
# Check service health
systemctl status mosquitto
# View live broker logs
journalctl -u mosquitto -f
# Confirm listening ports
ss -tlnp | grep 8883
# Round-trip test over TLS with credentials
mosquitto_sub --cafile /etc/mosquitto/certs/ca.crt \
-h localhost -p 8883 -t verify/# \
-u mqttuser -P yourpassword -v &
mosquitto_pub --cafile /etc/mosquitto/certs/ca.crt \
-h localhost -p 8883 -t verify/ping -m pong \
-u mqttuser -P yourpassword
The subscriber should print verify/ping pong.
Troubleshooting
- Connection refused on 8883: Check
journalctl -u mosquitto -efor certificate path errors. Ensuremosquittouser can read/etc/mosquitto/certs/. - "Not authorised" with correct credentials: Confirm
allow_anonymous falseis set andpassword_filepath is correct. Runmosquitto_passwd -vto test the file. - ACL silently drops publishes: Enable verbose logging by adding
log_type allto your config temporarily; look forACL check failedlines in the journal. - TLS handshake failure from remote clients: Clients need
ca.crt. If the server cert CN does not match the hostname clients connect to, add a SAN extension to the cert or use--insecureonly for testing. - Config changes not taking effect:
systemctl reloadre-reads the config; a fullsystemctl restartdrops all active sessions — use reload during operation.
Frequently asked questions
- Can I use a Let's Encrypt certificate instead of a self-signed CA?
- Yes. Set certfile and keyfile to your Let's Encrypt fullchain.pem and privkey.pem paths. You can omit cafile since clients trust public CAs by default. Add a systemd timer or certbot deploy-hook to reload Mosquitto after renewal.
- What is the difference between MQTT QoS 0, 1, and 2?
- QoS 0 fires and forgets with no delivery guarantee. QoS 1 guarantees at-least-once delivery with acknowledgement. QoS 2 guarantees exactly-once delivery using a four-step handshake, at the cost of higher latency and broker storage.
- How do I bridge two Mosquitto brokers together?
- Add a connection block to mosquitto.conf with the remote broker's address, topics to bridge, and credentials. Use bridge_cafile and bridge_certfile if the remote uses TLS. Bridging is one-way or bidirectional depending on the topic direction settings.
- Why does Mosquitto reject my client even though credentials are correct?
- Check the ACL file. If an ACL file is configured and a user has no matching rule for a topic, Mosquitto denies access silently by default. Add log_type all temporarily and inspect journalctl output for ACL check failed messages.
- Is Mosquitto suitable for high-throughput production workloads?
- Mosquitto handles tens of thousands of concurrent connections well on modest hardware, but it is single-threaded per listener. For very high message rates or complex routing needs, consider HiveMQ or EMQX. For most IoT and home-automation workloads, Mosquitto is more than adequate.
Related guides
Configure Prometheus Alertmanager
Configure Prometheus Alertmanager with routing trees, receivers, inhibition rules, grouping, Go templates, and PagerDuty/Slack on-call integrations.
Build an Intranet Server on Linux
Set up a complete small-office intranet on one Linux box: Nginx web server, dnsmasq local DNS, Samba file sharing, and a Wiki.js team wiki.
Build an nftables Firewall Script
Build a complete nftables firewall from scratch: tables, chains, sets, default-deny input policy, service allowlisting, and persistent systemd configuration.
Caddy as a Reverse Proxy
Set up Caddy as a reverse proxy with automatic HTTPS, load balancing, WebSocket passthrough, reusable snippets, and header control — no certbot required.