Mosquitto MQTT Broker Advanced Configuration

Eclipse Mosquitto is a lightweight, open-source MQTT broker that forms the backbone of IoT communication stacks on Linux. This guide covers advanced Mosquitto configuration including TLS encryption, multiple authentication backends, ACL rules for topic-level authorization, broker bridging, WebSocket support, and persistence for reliable message delivery.

Prerequisites

  • Ubuntu 20.04/22.04 or CentOS 8/Rocky Linux 8+
  • Root or sudo access
  • openssl installed (for TLS certificate generation)
  • A domain name (for production TLS)
  • Port 1883 (MQTT), 8883 (MQTT/TLS), and 9001 (WebSocket) available

Install Mosquitto

Ubuntu/Debian:

# Add official Mosquitto PPA for the latest version
sudo add-apt-repository ppa:mosquitto-dev/mosquitto-ppa -y
sudo apt update
sudo apt install -y mosquitto mosquitto-clients

sudo systemctl enable mosquitto
sudo systemctl start mosquitto

# Verify version
mosquitto -v  # Ctrl+C to stop
mosquitto --version

CentOS/Rocky Linux:

sudo dnf install -y epel-release
sudo dnf install -y mosquitto
sudo systemctl enable --now mosquitto

Backup and clear the default config:

sudo cp /etc/mosquitto/mosquitto.conf /etc/mosquitto/mosquitto.conf.bak
# Use /etc/mosquitto/conf.d/ for modular configuration

TLS Encryption Setup

Enable encrypted MQTT connections (MQTT over TLS on port 8883):

# Create a CA and server certificate
sudo mkdir -p /etc/mosquitto/certs
cd /etc/mosquitto/certs

# Generate CA key and certificate
sudo openssl genrsa -out ca.key 4096
sudo openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
  -subj "/C=US/ST=State/O=MyOrg/CN=MQTT CA"

# Generate server key and certificate request
sudo openssl genrsa -out server.key 2048
sudo openssl req -new -key server.key -out server.csr \
  -subj "/C=US/ST=State/O=MyOrg/CN=mqtt.example.com"

# Sign the server certificate with the CA
sudo openssl x509 -req -days 3650 -in server.csr \
  -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt

sudo chown mosquitto:mosquitto /etc/mosquitto/certs/*.{key,crt}
sudo chmod 600 /etc/mosquitto/certs/*.key

Configure TLS in Mosquitto:

cat > /etc/mosquitto/conf.d/tls.conf << 'EOF'
# TLS listener
listener 8883
protocol mqtt

# Certificate files
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key

# Require client certificates (optional - for mutual TLS)
# require_certificate true

# TLS version
tls_version tlsv1.2

# Allow TLS 1.3
# tls_version tlsv1.3

# Disable unencrypted connections on port 1883 (comment out to allow both)
# listener 1883
# Remove the default listener if you want TLS-only:
EOF

sudo systemctl restart mosquitto

Test TLS connection:

# Subscribe with TLS (using CA cert for verification)
mosquitto_sub -h localhost -p 8883 \
  --cafile /etc/mosquitto/certs/ca.crt \
  -t "test/#" -v

# Publish with TLS
mosquitto_pub -h localhost -p 8883 \
  --cafile /etc/mosquitto/certs/ca.crt \
  -t "test/hello" -m "Hello TLS"

Authentication Backends

Password file authentication:

# Create password file
sudo touch /etc/mosquitto/passwd
sudo chown mosquitto:mosquitto /etc/mosquitto/passwd
sudo chmod 600 /etc/mosquitto/passwd

# Add users
sudo mosquitto_passwd -b /etc/mosquitto/passwd iotdevice devicepassword
sudo mosquitto_passwd -b /etc/mosquitto/passwd homeassistant hapassword
sudo mosquitto_passwd -b /etc/mosquitto/passwd nodered nrpassword

# View users (hashed, not plain text)
sudo cat /etc/mosquitto/passwd

Configure password file authentication:

cat > /etc/mosquitto/conf.d/auth.conf << 'EOF'
# Disable anonymous access
allow_anonymous false

# Password file
password_file /etc/mosquitto/passwd
EOF

sudo systemctl restart mosquitto

# Test authentication
mosquitto_pub -h localhost -p 1883 \
  -u iotdevice -P devicepassword \
  -t "test/auth" -m "authenticated"

Plugin-based authentication (mosquitto-auth-plug):

# Install mosquitto-auth-plug for MySQL/Redis/HTTP backends
# This requires compiling from source or using a pre-built package

# Alternative: use mosquitto-plugin-auth for newer versions
# Check plugin availability:
mosquitto --help 2>&1 | grep plugin

# HTTP-based authentication (delegates to an auth service)
cat >> /etc/mosquitto/conf.d/auth.conf << 'EOF'

# HTTP auth backend (requires mosquitto-auth-plug or similar)
# auth_plugin /usr/lib/mosquitto_auth_plug.so
# auth_opt_backends http
# auth_opt_http_ip 127.0.0.1
# auth_opt_http_port 3000
# auth_opt_http_getuser_uri /auth/user
# auth_opt_http_superuser_uri /auth/superuser
# auth_opt_http_aclcheck_uri /auth/acl
EOF

ACL Rules and Topic Authorization

ACL files control which users can publish/subscribe to which topics:

cat > /etc/mosquitto/acl << 'EOF'
# Format:
# user <username>
# topic [read|write|readwrite] <topic>

# Home Assistant - read all, write sensors only
user homeassistant
topic readwrite homeassistant/#
topic read home/#

# Node-RED - can read everything, write to processed topics
user nodered
topic read home/#
topic read homeassistant/#
topic write processed/#
topic write alerts/#

# IoT device - can only write to its own topics
user iotdevice
topic write home/device001/#
topic read home/device001/commands

# IoT device 2 with variable topic (using %c for client ID)
# user iotdevice_template
# topic write home/%c/#    # %c = MQTT client ID
# topic write home/%u/#    # %u = username

# Pattern-based ACL for all users
# pattern read $SYS/#    # Allow reading Mosquitto sys stats
EOF

sudo chown mosquitto:mosquitto /etc/mosquitto/acl
sudo chmod 640 /etc/mosquitto/acl

Add ACL file reference to config:

echo "acl_file /etc/mosquitto/acl" | sudo tee -a /etc/mosquitto/conf.d/auth.conf
sudo systemctl restart mosquitto

WebSocket Support

Enable WebSocket for browser-based MQTT clients:

cat > /etc/mosquitto/conf.d/websockets.conf << 'EOF'
# WebSocket listener (for browser clients)
listener 9001
protocol websockets

# WebSocket with TLS (WSS)
listener 9443
protocol websockets
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
EOF

sudo systemctl restart mosquitto

# Test with mosquitto_sub (WebSocket mode)
mosquitto_sub -h localhost -p 9001 -t "test/#" -v \
  -u iotdevice -P devicepassword

Browser-based client (JavaScript MQTT.js):

<!-- Include MQTT.js via CDN -->
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
<script>
const client = mqtt.connect('wss://mqtt.example.com:9443', {
    username: 'nodered',
    password: 'nrpassword',
    rejectUnauthorized: false  // Only for self-signed certs in dev
});

client.on('connect', () => {
    console.log('Connected to MQTT broker');
    client.subscribe('home/#', { qos: 1 });
});

client.on('message', (topic, payload) => {
    console.log(`${topic}: ${payload.toString()}`);
});
</script>

Broker Bridging

Bridge two Mosquitto brokers to relay messages between them (e.g., local IoT broker to cloud broker):

cat > /etc/mosquitto/conf.d/bridge.conf << 'EOF'
# Bridge to a remote MQTT broker (e.g., cloud MQTT)
connection cloud-bridge
address cloud-mqtt.example.com:8883

# Topics to bridge
# local-prefix → remote-prefix
# Direction: both = bidirectional, in = remote→local, out = local→remote
topic sensors/# out 1 home/ remote/home/
topic commands/# in 1 remote/ home/

# Authentication for remote broker
remote_username cloud_device
remote_password cloudpassword

# TLS for bridge connection
bridge_cafile /etc/mosquitto/certs/cloud-ca.crt
bridge_tls_version tlsv1.2

# Keep alive and reconnect settings
keepalive_interval 60
connection_messages true
restart_timeout 5

# QoS level for bridged messages
bridge_attempt_unsubscribe false
EOF

sudo systemctl restart mosquitto

# Verify bridge is connected
mosquitto_sub -h localhost -p 1883 -u homeassistant -P hapassword \
  -t '$SYS/broker/connection/cloud-bridge/state' -C 1
# Should return: 1 (connected)

Persistence Configuration

Configure message persistence for durable delivery:

cat > /etc/mosquitto/conf.d/persistence.conf << 'EOF'
# Enable persistence
persistence true
persistence_location /var/lib/mosquitto/

# Persistence file name
persistence_file mosquitto.db

# Autosave interval (seconds, 0 = save on disconnect only)
autosave_interval 300

# Maximum QoS 2 message inflight limit
max_inflight_messages 20

# Maximum queued messages per client
max_queued_messages 100

# Retain messages persist across restarts when persistence is enabled
# Retained messages are written to the persistence file
EOF

sudo chown -R mosquitto:mosquitto /var/lib/mosquitto
sudo systemctl restart mosquitto

Monitoring and Logging

cat > /etc/mosquitto/conf.d/logging.conf << 'EOF'
# Log destinations
log_dest file /var/log/mosquitto/mosquitto.log
log_dest stdout

# Log types
log_type error
log_type warning
log_type notice
log_type information
# log_type debug  # Very verbose, only for troubleshooting

# Log timestamp
log_timestamp true
log_timestamp_format %Y-%m-%dT%H:%M:%S
EOF

sudo mkdir -p /var/log/mosquitto
sudo chown mosquitto:mosquitto /var/log/mosquitto

Monitor via $SYS topics:

# Subscribe to all system stats
mosquitto_sub -h localhost -p 1883 \
  -u homeassistant -P hapassword \
  -t '$SYS/#' -v &

# Key $SYS topics to watch:
# $SYS/broker/clients/connected    - Active connections
# $SYS/broker/messages/received    - Total messages in
# $SYS/broker/messages/sent        - Total messages out
# $SYS/broker/bytes/received       - Bytes received
# $SYS/broker/bytes/sent           - Bytes sent
# $SYS/broker/subscriptions/count  - Active subscriptions
# $SYS/broker/load/messages/+      - Message load averages

# View real-time stats
mosquitto_sub -h localhost -p 1883 \
  -u homeassistant -P hapassword \
  -t '$SYS/broker/clients/connected' \
  -t '$SYS/broker/messages/received' \
  -v

Troubleshooting

"Connection refused" on port 1883:

# Check if Mosquitto is running
sudo systemctl status mosquitto
sudo journalctl -u mosquitto -n 30

# Check listening ports
ss -tlnp | grep -E "1883|8883|9001"

# Verify config syntax
sudo mosquitto -c /etc/mosquitto/mosquitto.conf --test-options

Authentication failures:

# Test with explicit credentials
mosquitto_pub -h localhost -p 1883 -u testuser -P testpass -t test -m msg -d

# Check if anonymous access is properly disabled
grep allow_anonymous /etc/mosquitto/conf.d/auth.conf

# Verify password file format
sudo cat /etc/mosquitto/passwd | head -5
# Should look like: username:$7$...(bcrypt hash)

ACL errors - "Not authorized":

# Enable debug logging temporarily
echo "log_type all" | sudo tee /etc/mosquitto/conf.d/debug.conf
sudo systemctl restart mosquitto

# Watch logs for ACL denials
sudo tail -f /var/log/mosquitto/mosquitto.log | grep -i "denied\|acl\|auth"

# Remove debug config when done
sudo rm /etc/mosquitto/conf.d/debug.conf
sudo systemctl restart mosquitto

TLS handshake failures:

# Test TLS with OpenSSL
openssl s_client -connect localhost:8883 -CAfile /etc/mosquitto/certs/ca.crt

# Check certificate expiry
openssl x509 -in /etc/mosquitto/certs/server.crt -noout -dates

# Verify CA chain
openssl verify -CAfile /etc/mosquitto/certs/ca.crt /etc/mosquitto/certs/server.crt

Conclusion

Advanced Mosquitto configuration transforms a basic MQTT broker into a secure, production-grade messaging backbone for IoT deployments. TLS encryption protects data in transit, ACL rules enforce the principle of least privilege for each device and service, WebSocket support enables browser-based dashboards, and broker bridging connects on-premises sensors to cloud platforms. Deploy Mosquitto with persistence enabled to ensure QoS 1 and 2 messages survive broker restarts.