17  MQTT Security

In 60 Seconds

Every production MQTT deployment must implement three security layers: TLS encryption on port 8883 (not plaintext 1883), authentication via username/password or client certificates, and topic-level access control lists (ACLs) that restrict which clients can publish or subscribe to specific topics. Without these, attackers can eavesdrop on sensor data, inject fake commands, or impersonate devices.

17.1 Learning Objectives

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

  • Implement Transport Security: Configure TLS/SSL on port 8883 for encrypted MQTT communication and explain why plaintext port 1883 is unacceptable in production
  • Compare Authentication Methods: Distinguish between username/password, client certificates, and JWT-based authentication, and justify when each is most appropriate
  • Design Access Control Policies: Construct topic-level ACL rules that enforce least-privilege access for sensors, actuators, and dashboards
  • Analyze Attack Surfaces: Evaluate which attack vectors (eavesdropping, injection, impersonation, DoS) remain open under different security configurations
  • Diagnose Security Pitfalls: Identify and correct common mistakes including hardcoded credentials, overly permissive ACLs, and disabled certificate validation
  • Calculate Security Trade-offs: Assess TLS handshake overhead, JWT token lifetime, and ACL rule complexity to select appropriate configurations for constrained IoT deployments
  • MQTT: Message Queuing Telemetry Transport — pub/sub protocol optimized for constrained IoT devices over unreliable networks
  • Broker: Central server routing messages from publishers to all matching subscribers by topic pattern
  • Topic: Hierarchical string (e.g., home/bedroom/temperature) used to route messages to interested subscribers
  • QoS Level: Quality of Service 0/1/2 trading delivery guarantee for message overhead
  • Retained Message: Last message on a topic stored by broker for immediate delivery to new subscribers
  • Last Will and Testament: Pre-configured message published by broker when a client disconnects ungracefully
  • Persistent Session: Broker stores subscriptions and pending messages allowing clients to resume after disconnection

17.2 For Beginners: MQTT Security

Securing MQTT means protecting the data your IoT devices send and receive. This includes encrypting communications (so nobody can eavesdrop), authenticating devices (so only trusted devices connect), and authorizing access (so devices can only see the data they should). Without security, anyone could read or inject fake sensor data.

“Someone could be listening to my temperature readings!” Sammy the Sensor whispered nervously.

Max the Microcontroller got serious. “That’s why MQTT security has three layers. First, TLS encryption – it scrambles every message between you and the broker. Even if someone intercepts the data, they just see random gibberish. It’s like speaking in a secret code.”

“Second, authentication,” said Lila the LED. “Every device needs a username and password – or even better, a unique certificate – to connect to the broker. No ID, no entry. It stops random devices from joining your network and publishing fake data.”

Bella the Battery added the third layer: “Authorization controls what each device can do. Sammy can publish to garden/temperature but NOT to security/door-lock. The broker checks permissions for every action. It’s like having a library card that lets you borrow books but not take the computers home. All three layers together – encryption, authentication, authorization – keep our IoT network safe!”

17.3 Prerequisites

Before diving into this chapter, you should be familiar with:

17.4 Why MQTT Security Matters

Without proper security, attackers can:

  • Eavesdrop on sensor data (privacy breach)
  • Publish fake commands (actuator manipulation)
  • Deny service (flood broker with messages)
  • Impersonate devices (inject malicious data)
Security Is Not Optional

Every production MQTT deployment MUST implement:

  1. Encryption (TLS/SSL)
  2. Authentication (verify identity)
  3. Authorization (access control)
Try It: Threat Impact Estimator

17.5 Transport Layer Security (TLS/SSL)

Always use MQTTS (MQTT over TLS) in production:

Port Protocol Security
1883 MQTT Unencrypted (testing only)
8883 MQTTS TLS encrypted (production)

17.5.1 Python Example with TLS

# Requires paho-mqtt 2.0+
import paho.mqtt.client as mqtt
import ssl

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

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

# Connect to secure port
client.connect("broker.example.com", 8883)

17.5.2 ESP32 Example with TLS

#include <WiFiClientSecure.h>
#include <PubSubClient.h>

// Root CA certificate (from broker)
const char* ca_cert = R"(
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIJAJC1...
-----END CERTIFICATE-----
)";

WiFiClientSecure espClient;
PubSubClient client(espClient);

void setup() {
    espClient.setCACert(ca_cert);
    client.setServer("broker.example.com", 8883);
}

17.6 Authentication Methods

17.6.1 Username/Password Authentication

The simplest authentication method:

client.username_pw_set("device_001", "SecurePassword123!")
client.connect("broker.example.com", 8883)

Best practices:

  • Use unique credentials per device
  • Store passwords securely (not in source code)
  • Rotate credentials periodically
  • Use strong passwords (16+ characters)
Try It: Password Strength Analyzer

17.6.2 Client Certificate Authentication

More secure than passwords - device identity proven by certificate:

client.tls_set(
    certfile="/path/to/device.crt",
    keyfile="/path/to/device.key"
)
# No username/password needed - certificate proves identity

Advantages:

  • No password to leak or brute-force
  • Device identity cryptographically verified
  • Easier to revoke (add to Certificate Revocation List)

Enabling TLS on MQTT adds a one-time handshake cost per connection. For a sensor connecting once per day with 100ms RTT:

TLS 1.2 handshake (2 RTTs): \[ T_{\text{TLS1.2}} = 2 \times \text{RTT} = 2 \times 100\text{ ms} = 200\text{ ms} \]

TLS 1.3 handshake (1 RTT, improved): \[ T_{\text{TLS1.3}} = 1 \times \text{RTT} = 100\text{ ms} \]

Energy cost (8 mA TX current, 6 handshake packets, 15 ms TX time per packet): \[ E_{\text{handshake}} = 6 \times (8\text{ mA} \times 15\text{ ms}) = 0.72\text{ mAs} \]

Amortized per message (connect once, send \(N\) messages): \[ E_{\text{per\_msg}} = \frac{0.72}{N} + E_{\text{MQTT}} \]

For \(N = 1440\) (1 msg/min, 1 day session): \[ E_{\text{per\_msg}} = \frac{0.72}{1440} + 0.4 = 0.0005 + 0.4 \approx 0.4\text{ mAs} \]

Bandwidth overhead: TLS 1.3 handshake: ~3–5 KB (certificates exchanged) TLS 1.2 handshake: ~5–10 KB (larger due to additional round-trip messages) MQTT message: ~50 bytes (typical sensor reading)

Takeaway: Keep MQTT connections persistent for multiple messages to amortize TLS handshake cost. Reconnecting for every message adds 100–200 ms latency (1 RTT for TLS 1.3, 2 RTT for TLS 1.2) and proportional energy overhead per reconnect. For always-connected devices sending many messages per session, TLS handshake cost falls below 0.1% of total energy.

17.6.3 TLS Handshake Overhead Calculator

Estimate the latency, energy, and bandwidth overhead of TLS handshakes for your MQTT deployment. Adjust RTT, TLS version, session length, and message rate to see how persistent connections amortize the cost.

17.6.4 Token-Based Authentication (JWT)

Modern brokers support JWT tokens for scalable device authentication.

JSON Web Tokens provide a stateless authentication mechanism ideal for large-scale IoT deployments.

JWT Structure for MQTT:

Header.Payload.Signature

Header: {"alg": "RS256", "typ": "JWT"}
Payload: {
  "sub": "device_001",        # Device ID (subject)
  "iat": 1702834567,          # Issued at timestamp
  "exp": 1702838167,          # Expiration (1 hour later)
  "aud": "mqtt.example.com",  # Target broker
  "scope": ["publish:sensors/#", "subscribe:commands/#"]
}

Python implementation:

import jwt
import time
from cryptography.hazmat.primitives import serialization

# Load device private key
with open("device_private.pem", "rb") as key_file:
    private_key = serialization.load_pem_private_key(
        key_file.read(), password=None
    )

def generate_mqtt_token():
    payload = {
        "sub": "sensor_001",
        "iat": int(time.time()),
        "exp": int(time.time()) + 3600,  # 1 hour validity
        "aud": "mqtt.example.com",
        "scope": ["publish:sensors/temperature", "subscribe:commands/#"]
    }
    return jwt.encode(payload, private_key, algorithm="RS256")

# Connect with JWT
token = generate_mqtt_token()
client.username_pw_set("", token)  # Empty username, token as password

Security best practices:

Practice Recommendation
Algorithm Use RS256/ES256 (asymmetric), not HS256
Expiration 1-24 hours max
Scope claims Implement fine-grained topic permissions
Key rotation Rotate signing keys quarterly

17.6.5 JWT Token Lifetime Calculator

Balance security (short tokens) against reconnection overhead (frequent renewals). Adjust token lifetime, device count, and connection parameters to find the optimal trade-off.

17.7 Access Control Lists (ACLs)

Restrict which topics each client can access:

# Mosquitto ACL file example (/etc/mosquitto/acl.conf)

# Sensor can only publish its own data
user sensor_001
topic read home/+/temperature
topic write home/sensor_001/#

# Actuator can only receive commands and publish status
user actuator_001
topic read home/commands/actuator_001
topic write home/status/actuator_001

# Dashboard can read everything but write nothing
user dashboard
topic read home/#

Security principle: Least privilege - devices only access topics they need.

17.7.1 ACL Patterns

Pattern Example Description
Exact match topic read sensors/temp Only this specific topic
Single wildcard topic write sensors/+/data Any device’s data topic
Multi wildcard topic read sensors/# All under sensors/
Pattern substitution topic write sensors/%u/data %u = username

17.7.2 ACL Rule Complexity Estimator

Estimate the number of ACL rules and configuration effort for your deployment. Wildcards and pattern substitution reduce rule count significantly compared to per-device exact rules.

Test your understanding of MQTT security concepts by matching terms to definitions and ordering the steps of the TLS handshake process.

17.8 Summary

Security essentials:

Layer Implementation
Transport TLS on port 8883
Authentication Unique credentials per device
Authorization Topic-level ACLs
Monitoring Log analysis and anomaly detection

Remember:

  • Never use port 1883 in production
  • Never disable certificate validation
  • Always implement least-privilege ACLs
  • Rotate credentials regularly

17.9 See Also

17.10 What’s Next

Now that you can configure TLS, design ACLs, and evaluate MQTT attack surfaces, these chapters extend your knowledge further:

Chapter Focus Why Read It
MQTT Advanced Topics Packet structure and topic design patterns Apply security knowledge to well-structured topic hierarchies that ACLs can cleanly target
MQTT Labs and Implementation Hands-on broker setup and client code Practice configuring TLS, credentials, and ACLs on a real Mosquitto instance
Encryption Architecture and Levels TLS/SSL internals and certificate chains Understand the full TLS handshake and certificate validation process behind MQTT over port 8883
Authentication and Access Control Concepts RBAC, ABAC, and IAM models Design scalable ACL strategies using established access-control frameworks
Cyber Security Methods Broader IoT security techniques Put MQTT security in context alongside network segmentation, intrusion detection, and incident response
Security Threat Categories and Attack Scenarios MQTT-specific attack vectors and mitigations Analyse real-world MQTT exploits (Shodan exposure, broker flooding, credential stuffing) in depth