1198  MQTT Security: TLS, Authentication, and Access Control

1198.1 MQTT Security

Securing MQTT communications is essential for production IoT deployments. This chapter covers Transport Layer Security (TLS), authentication mechanisms, and Access Control Lists (ACLs) for robust MQTT security.

1198.2 Learning Objectives

By the end of this chapter, you will be able to:

  • Implement TLS Encryption: Configure secure MQTT connections on port 8883
  • Configure Authentication: Set up username/password and certificate-based authentication
  • Design Access Control: Create topic-level ACL policies for multi-tenant systems
  • Avoid Common Security Mistakes: Identify and prevent production security pitfalls
WarningCritical Security Warning

NEVER use public MQTT brokers (test.mosquitto.org) for production systems! These are unencrypted, unauthenticated, and anyone can subscribe to your topics. Always use: - TLS encryption (port 8883) - Username/password OR client certificates - Topic-level ACLs - A private broker (self-hosted or managed cloud service)

1198.3 Security Layers

MQTT security consists of three layers:

Layer Purpose Implementation
Transport Encrypt data in transit TLS/SSL on port 8883
Authentication Verify client identity Username/password, certificates
Authorization Control topic access Access Control Lists (ACLs)

1198.4 TLS Encryption

NoteTLS vs SSL

TLS (Transport Layer Security) is the successor to SSL. Modern MQTT implementations use TLS 1.2 or 1.3. Always use TLS, not the deprecated SSL.

Standard Ports: - 1883: Unencrypted MQTT (development only!) - 8883: Encrypted MQTT over TLS (production) - 443: MQTT over WebSocket with TLS (browser-based clients)

1198.4.1 Step 1: Generate SSL/TLS Certificates

# Create certificate directory
sudo mkdir -p /etc/mosquitto/certs
cd /etc/mosquitto/certs

# Generate CA certificate
sudo openssl req -new -x509 -days 365 -extensions v3_ca \
  -keyout ca.key -out ca.crt \
  -subj "/C=US/ST=State/L=City/O=IoTClass/CN=CA"

# Generate server key and certificate
sudo openssl genrsa -out server.key 2048
sudo openssl req -new -out server.csr -key server.key \
  -subj "/C=US/ST=State/L=City/O=IoTClass/CN=mqtt.local"
sudo openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
  -CAcreateserial -out server.crt -days 365

# Set permissions
sudo chmod 644 /etc/mosquitto/certs/*.crt
sudo chmod 600 /etc/mosquitto/certs/*.key

1198.4.2 Step 2: Configure Mosquitto with Security

Edit /etc/mosquitto/mosquitto.conf:

# Default listener (disabled for production)
listener 1883
allow_anonymous false

# TLS listener
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
require_certificate false

# Password file
password_file /etc/mosquitto/passwd

# Logging
log_dest file /var/log/mosquitto/mosquitto.log
log_type all

1198.4.3 Step 3: Create User Accounts

# Create password file with first user
sudo mosquitto_passwd -c /etc/mosquitto/passwd iotuser

# Add more users (without -c flag)
sudo mosquitto_passwd /etc/mosquitto/passwd admin

1198.4.4 Step 4: Restart Mosquitto

sudo systemctl restart mosquitto
sudo systemctl status mosquitto

1198.5 Python Client with TLS and Authentication

import paho.mqtt.client as mqtt
import ssl

# paho-mqtt 2.0+ requires CallbackAPIVersion
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.username_pw_set("iotuser", "your_password")

client.tls_set(
    ca_certs="/path/to/ca.crt",
    tls_version=ssl.PROTOCOL_TLS_CLIENT
)

def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code == 0:
        print("Securely connected!")
        client.subscribe("secure/test/#")
    else:
        print(f"Connection failed: {reason_code}")

def on_message(client, userdata, msg):
    print(f"[{msg.topic}] {msg.payload.decode()}")

client.on_connect = on_connect
client.on_message = on_message

client.connect("mqtt.local", 8883, 60)
client.loop_forever()

Expected Output:

Securely connected!
[secure/test/data] Hello from secure MQTT!

1198.6 Access Control Lists (ACLs)

ACLs control which clients can publish/subscribe to which topics.

1198.6.1 Mosquitto ACL Configuration

Create /etc/mosquitto/acl:

# Admin can access everything
user admin
topic readwrite #

# Sensor devices can only publish to their topics
user sensor_001
topic write sensors/001/#
topic read commands/001

# Dashboard can read everything, write nothing
user dashboard
topic read sensors/#
topic read devices/#

# Default: deny everything
topic deny #

Update mosquitto.conf:

acl_file /etc/mosquitto/acl

1198.7 Knowledge Checks

Question: Your smart lock uses MQTT over public internet. Security audit reveals credentials transmitted in plaintext. What’s the proper security configuration?

Explanation: MQTT over TLS (MQTTS) provides transport security. Default MQTT port 1883: Unencrypted - username, password, payload visible to network sniffers. Secure MQTT port 8883: TLS-encrypted TCP tunnel. Configuration: client.tls_set(ca_certs="ca.crt", certfile="client.crt", keyfile="client.key") enables TLS with mutual authentication. Security layers: (1) Transport encryption (TLS): Protects data in transit, (2) Authentication: Proves client identity, (3) Client certificates: Mutual TLS prevents impersonation, (4) Authorization (ACLs): Topic-level access control.

1198.8 Common Security Mistakes

CautionSecurity Pitfalls to Avoid
  1. Using port 1883 in production: Always use TLS (port 8883)

  2. Hardcoding credentials: Use environment variables or secure vaults

    # BAD
    password = "mysecretpassword"
    
    # GOOD
    import os
    password = os.environ.get("MQTT_PASSWORD")
  3. Using self-signed certificates without CA verification: Vulnerable to MITM attacks

  4. Overly broad ACLs: Grant minimum necessary permissions

  5. Not rotating credentials: Change passwords and certificates regularly

  6. Logging sensitive data: Never log passwords or tokens

1198.9 Certificate-Based Authentication (Mutual TLS)

For the highest security, use client certificates instead of passwords:

import paho.mqtt.client as mqtt
import ssl

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)

# Configure mutual TLS (client certificate authentication)
client.tls_set(
    ca_certs="/path/to/ca.crt",
    certfile="/path/to/client.crt",
    keyfile="/path/to/client.key",
    tls_version=ssl.PROTOCOL_TLS_CLIENT
)

# No username/password needed - certificate is the identity
client.connect("mqtt.secure.com", 8883, 60)

1198.10 Testing Connection Security

# Test with mosquitto_pub (with authentication)
mosquitto_pub -h mqtt.local -p 8883 \
  -u iotuser -P your_password \
  --cafile /etc/mosquitto/certs/ca.crt \
  -t "secure/test" -m "Hello from terminal" -q 1

# Test without authentication (should fail)
mosquitto_pub -h mqtt.local -p 8883 \
  --cafile /etc/mosquitto/certs/ca.crt \
  -t "secure/test" -m "This will fail"

1198.11 Security Best Practices Checklist

  1. Transport Security
  2. Authentication
  3. Authorization
  4. Operations

1198.12 What’s Next

Continue to MQTT Labs for hands-on exercises implementing secure MQTT connections, including ESP32 labs with TLS and real-world authentication scenarios.

1198.13 See Also