MQTT Security

MQTT Audit Logging: What to Record and Why

A practical guide to MQTT audit logging: which events matter for security and compliance, what fields to capture, where logs come from in a managed setup, and how to build a simple pipeline.

MQTT audit logging pipeline showing broker connection events, authentication failures and admin actions flowing into a central log store
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

MQTT audit logging means recording who connected, who failed to connect, what changed in the configuration and which actions mattered, so you can investigate incidents and show auditors that controls work. This guide explains which events to record, which fields each entry needs, how long to keep them and how to assemble a log pipeline around a managed broker. It focuses on security and operational events, not on storing every message payload.

Audit Logs Versus Message Data

It helps to separate three kinds of records:

  • Audit logs: security-relevant events such as logins, failed logins, credential changes and administrative actions. Small, structured, kept for a defined period.
  • Operational logs: connection drops, errors, quota hits and performance signals used to keep the system running.
  • Message history: the telemetry itself, usually stored in a time-series database or historian for analytics.

Mixing them causes problems. Payload archives are large, may contain personal or confidential data, and bury the security events you actually need during an investigation. Keep audit logs lean and focused.

What to Record

Event Why it matters Key fields
Successful connection Shows which identity was active, when and from where Timestamp (UTC), client ID, username, source IP, protocol version, TLS yes/no
Failed authentication Detects guessing, leaked credentials and misconfigured devices Timestamp, attempted username, client ID, source IP, reason code
Disconnection Explains outages and session takeovers Timestamp, client ID, reason code, session duration
Authorisation denial Shows clients trying to reach topics they should not Client ID, topic filter, action, reason code
Quota or rate-limit event Identifies runaway devices and abuse Client ID, limit type, reason code (for example 0x97)
IP blocks Confirms automated defences are working Source IP, trigger, duration
Credential lifecycle Proves provisioning, rotation and revocation happen Identity, action, actor, timestamp
Administrative changes Who changed brokers, plans, alert rules or users Actor, action, object, old and new value
Command messages For control topics, who sent which command Topic, sender identity, command, result

The last row deserves attention. Telemetry rarely needs an audit trail, but commands that change equipment state often do. Record the command, the sending identity and the acknowledgement, not just the fact that a message passed through.

Fields Every Entry Needs

Whatever the source, normalise entries to a consistent structure:

{
  "ts": "2026-10-16T09:41:07.312Z",
  "event": "client.disconnected",
  "source": "connectmq-monitor",
  "client_id": "gw-plant1-01",
  "username": "gw-plant1-01",
  "ip": "203.0.113.24",
  "reason_code": "0x8E",
  "details": { "previous_state": "connected" }
}

Use UTC timestamps with milliseconds, keep event names stable, and never log passwords, tokens or full payloads containing personal data.

Where the Events Come From

In a self-hosted setup, the broker's own log files are the primary source. Mosquitto, for example, logs connections, disconnections and authentication failures when the relevant log_type options are enabled, and you ship those files to a central system.

With a managed broker, you combine what the platform exposes with what your own clients and applications record. It is important to be precise about which is which. On ConnectMQ the visible sources are:

  • Connection state topics: $SYS/broker/connection/{clientId}/state reports whether a client is connected, which you can subscribe to and record.
  • Portal dashboard and devices view: operational visibility into connected clients and topics.
  • Threshold alert rules and the alerts log: a record of when data crossed thresholds you defined.
  • MQTT 5 reason codes: returned to clients on refusal, including 0x97 for quota exceeded, which your clients can log.
  • Platform protections: flood protection and IP blocking after repeated failed logins run on the broker side.

These are operational signals, not a compliance audit trail. For a complete audit trail, record events from the client and application side into storage you control, and document administrative procedures in your own change records. This is a common shared-responsibility split with managed services; see the managed MQTT broker guide for how responsibilities divide.

Build a Simple Audit Pipeline

A small service that subscribes to connection state topics and writes structured lines to a file or log shipper gives you a reliable connection history. This example uses paho-mqtt 2.x and watches a known list of client IDs:

import json
import logging
from datetime import datetime, timezone
import paho.mqtt.client as mqtt

WATCHED_CLIENTS = ["gw-plant1-01", "gw-plant1-02", "dashboard-01"]

logging.basicConfig(filename="mqtt-audit.jsonl", level=logging.INFO, format="%(message)s")

def audit(event, **fields):
    entry = {"ts": datetime.now(timezone.utc).isoformat(timespec="milliseconds"),
             "event": event, "source": "connectmq-monitor", **fields}
    logging.info(json.dumps(entry))

def on_connect(client, userdata, flags, reason_code, properties):
    audit("monitor.connected", reason_code=str(reason_code))
    for cid in WATCHED_CLIENTS:
        client.subscribe(f"$SYS/broker/connection/{cid}/state", qos=1)

def on_message(client, userdata, msg):
    cid = msg.topic.split("/")[3]
    audit("client.state", client_id=cid, state=msg.payload.decode("utf-8", "replace"))

def on_disconnect(client, userdata, flags, reason_code, properties):
    audit("monitor.disconnected", reason_code=str(reason_code))

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="YOUR_CLIENT_ID",
                     protocol=mqtt.MQTTv5)
client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.tls_set()
client.on_connect = on_connect
client.on_message = on_message
client.on_disconnect = on_disconnect
client.reconnect_delay_set(min_delay=1, max_delay=60)
client.connect("YOUR_BROKER_HOST", 8883, keepalive=60)
client.loop_forever()

The JSON lines file can be collected by any log shipper and forwarded to the SIEM or log platform your organisation already uses. Note that the monitor logs its own disconnections too: gaps in your audit trail are themselves important events.

Log on the Client Side Too

Devices and applications see events the broker never reports to you, such as their own failed connection attempts and refused publishes. Make every client log:

  1. Connection attempts with the result reason code.
  2. Refused subscriptions (SUBACK codes of 0x80 and above).
  3. Refused publishes, especially 0x97 quota exceeded and 0x87 not authorised.
  4. Received commands, validation results and actions taken.
  5. Credential rotation events.

For gateways in plants, ship these logs to a central collector rather than keeping them only on the device. The MQTT OT security guide covers how to do that without opening inbound ports.

Retention, Integrity and Privacy

Audit logs are only useful if they are complete, trustworthy and lawful to keep.

  • Retention: set a period based on your regulatory, contractual and investigation needs, and document it. Delete logs when the period ends.
  • Integrity: write to append-only storage or a system that restricts deletion, and limit who can change logs.
  • Time synchronisation: use NTP on every logging host; mismatched clocks make timelines useless.
  • Privacy: IP addresses and usernames can be personal data. Collect what you need, protect access and apply your privacy policy.
  • Access: log access to the logs themselves.

Turning Logs Into Alerts

Logs nobody reads do not improve security. Start with a few high-value alerts:

  1. Many failed authentications for one username or from one IP in a short window.
  2. A known device connecting from an unexpected network.
  3. A gateway disconnected for longer than its expected maximum outage.
  4. Repeated quota or rate-limit refusals from one client.
  5. Any command on a control topic outside working hours or from an unexpected identity.

These map closely to the continuous verification ideas in zero trust for IoT messaging and to the event monitoring expectations in frameworks such as IEC 62443.

Audit Logging Checklist

  1. Defined list of security events and owners for each source.
  2. Consistent JSON structure with UTC timestamps.
  3. Connection state monitored for every critical client.
  4. Client-side logging of reason codes, refusals and commands.
  5. Administrative changes recorded in your change management process.
  6. Central, access-controlled storage with a documented retention period.
  7. Alerts on failed logins, unexpected disconnections and rate anomalies.
  8. Regular review that the pipeline itself is running.

Start Monitoring Your Broker with ConnectMQ

Create a private broker on the free Serverless plan at app.connectmq.com (no credit card), connect the monitor above with your generated credentials and watch connection events appear. If you want to experiment without credentials first, try the free public MQTT broker with test data. The MQTT security best practices article covers the controls your logs should be verifying.

Frequently Asked Questions

Should I log every MQTT message for auditing?

Usually not. Log security and administrative events, plus commands on control topics. Store telemetry separately in a historian or database if you need it for analytics.

What is the most important MQTT event to audit?

Failed authentication attempts, because they reveal guessing, leaked or expired credentials and misconfigured devices early.

How long should MQTT audit logs be kept?

There is no single answer. Retention depends on your regulatory, contractual and investigation requirements, so define a period, document it and enforce deletion when it ends.

Can I get connection events from a managed broker?

On ConnectMQ you can subscribe to $SYS/broker/connection/{clientId}/state for connection state and combine it with client-side logs of reason codes to build your own connection history.

Related articles

How to Rotate MQTT Credentials Without Downtime

A step-by-step dual-credential strategy for rotating MQTT usernames and passwords across a fleet: stage the new credential, switch with fallback, verify and only then revoke the old one.

7 min read

Storing MQTT Credentials Securely on Embedded Devices

A practical comparison of ways to protect MQTT usernames and passwords on ESP32 and Linux devices, from encrypted NVS and flash encryption to secure elements and TPM-backed systemd credentials.

7 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.