Wireshark for MQTT: How to Capture and Decode Industrial IoT Traffic

By | April 10, 2026

MQTT (MQ Telemetry Transport) is the most widely used protocol in industrial IoT. It connects sensors, PLCs, gateways, and edge devices to cloud platforms and SCADA historians using a lightweight publish/subscribe model over TCP.

Wireshark fully decodes MQTT — every CONNECT, PUBLISH, SUBSCRIBE, and DISCONNECT message, including topic names, QoS levels, payloads, and client IDs — all in plain text.

MQTT runs on TCP port 1883 (unencrypted) and TCP port 8883 (TLS encrypted). Wireshark decodes port 1883 automatically. TLS traffic on port 8883 requires decryption keys.

This guide covers capture setup, verified display filters, how to read decoded MQTT packets, and how to diagnose the most common MQTT problems in industrial environments.

1. How MQTT Appears in Wireshark

Wireshark decodes MQTT as a single protocol layer on top of TCP:

LayerWhat It Shows
TCPPort 1883 (or 8883 for TLS), TCP handshake, keep-alive
MQTTMessage type, topic, QoS, payload, client ID, return codes

The Info column shows a summary like:

Connect Command
Connect Ack
Publish Message [sensor/temperature]  (QoS 1, id=1)
Publish Ack (id=1)
Subscribe Request (id=2) [plant/alarms/#]
Subscribe Ack (id=2)
Disconnect Req

2. How to Capture MQTT Traffic

Capture Filter

tcp port 1883

For TLS-encrypted MQTT:

tcp port 8883

Where to Capture

LocationWhen to Use
On the MQTT broker serverSee all client connections, publishes, and subscriptions
On the IoT gatewaySee what the gateway sends to the broker
On a network switch (port mirroring)Non-intrusive capture between devices and broker
On the edge deviceIf you need to verify what the device actually sends

3. Decoding MQTT on Non-Standard Ports

Wireshark decodes MQTT automatically on port 1883. Some brokers use custom ports (e.g., 1884, 8080, 9001 for WebSocket).

Fix: Use “Decode As”

  1. Right-click a packet on the non-standard port
  2. Select Decode As…
  3. Set: Field = TCP port, Value = your port, Current = MQTT
  4. Click OK

4. Display Filters for MQTT

All filter field names verified against the official Wireshark MQTT Display Filter Reference.

Basic Filters

FilterWhat It Shows
mqttAll MQTT traffic
tcp.port == 1883All traffic on MQTT port
tcp.port == 8883All MQTT-over-TLS traffic

Message Type Filters

FilterWhat It Shows
mqtt.msgtype == 1CONNECT
mqtt.msgtype == 2CONNACK
mqtt.msgtype == 3PUBLISH
mqtt.msgtype == 4PUBACK (QoS 1 acknowledgment)
mqtt.msgtype == 5PUBREC (QoS 2 step 1)
mqtt.msgtype == 6PUBREL (QoS 2 step 2)
mqtt.msgtype == 7PUBCOMP (QoS 2 step 3)
mqtt.msgtype == 8SUBSCRIBE
mqtt.msgtype == 9SUBACK
mqtt.msgtype == 10UNSUBSCRIBE
mqtt.msgtype == 11UNSUBACK
mqtt.msgtype == 12PINGREQ
mqtt.msgtype == 13PINGRESP
mqtt.msgtype == 14DISCONNECT

Connection Filters

FilterWhat It Shows
mqtt.clientidClient ID string
mqtt.clientid == "gateway-01"Traffic from a specific client
mqtt.conack.valCONNACK return code
mqtt.conack.val == 0Successful connections only
mqtt.conack.val != 0Failed connections only
mqtt.conflag.cleansessClean Session flag
mqtt.conflag.willflagWill Flag (LWT configured)
mqtt.conflag.unameUsername present
mqtt.conflag.passwdPassword present
mqtt.kaliveKeep-Alive interval value

Publish and Subscribe Filters

FilterWhat It Shows
mqtt.topicTopic name in PUBLISH or SUBSCRIBE
mqtt.topic contains "temperature"Topics containing “temperature”
mqtt.topic contains "alarm"Topics containing “alarm”
mqtt.msgMessage payload (raw bytes)
mqtt.msg_textMessage payload (as text, Wireshark 3.2+)
mqtt.msgidMessage Identifier (for QoS 1 and 2)
mqtt.qosQoS level (0, 1, or 2)
mqtt.dupflagDuplicate flag (retransmitted message)
mqtt.retainRetain flag

MQTT v5.0 Filters

FilterWhat It Shows
mqtt.connack.reason_codeCONNACK reason code (v5.0)
mqtt.disconnect.reason_codeDISCONNECT reason code (v5.0)
mqtt.propertiesMQTT v5.0 properties
mqtt.prop_keyUser property key
mqtt.prop_valueUser property value

Combination Examples

All PUBLISH messages on a specific topic:

mqtt.msgtype == 3 && mqtt.topic contains "sensor/temperature"

Failed connection attempts:

mqtt.conack.val != 0

All messages from a specific client:

mqtt.clientid == "plc-gateway-01"

QoS 1 messages that have not been acknowledged:

mqtt.msgtype == 3 && mqtt.qos == 1 && !mqtt.msgtype == 4

Keep-alive pings:

mqtt.msgtype == 12 || mqtt.msgtype == 13

5. How to Read a Decoded MQTT Packet

CONNECT Packet

MQ Telemetry Transport Protocol, Connect Command
    Header Flags: 0x10 (Connect Command)
    Msg Len: 45
    Protocol Name: MQTT
    Version: MQTT v3.1.1 (4)
    Connect Flags: 0xc2 (User Name, Password, Clean Session)
    Keep Alive: 60
    Client ID: gateway-01
    User Name: admin
    Password: ****

PUBLISH Packet

MQ Telemetry Transport Protocol, Publish Message
    Header Flags: 0x32 (Publish Message, QoS 1)
    Msg Len: 38
    Topic: plant/line1/temperature
    Message Identifier: 1
    Message: 23.5

CONNACK Packet

MQ Telemetry Transport Protocol, Connect Ack
    Header Flags: 0x20 (Connect Ack)
    Msg Len: 2
    Acknowledge Flags: 0x00
    Return Code: Connection Accepted (0)

6. What a Healthy MQTT Session Looks Like

#DirectionMQTT Info
1Client → BrokerTCP SYN
2Broker → ClientTCP SYN-ACK
3Client → BrokerTCP ACK
4Client → BrokerConnect Command (Client ID, credentials, keep-alive)
5Broker → ClientConnect Ack (Return Code: 0 = Accepted)
6Client → BrokerSubscribe Request [plant/line1/#]
7Broker → ClientSubscribe Ack
8Client → BrokerPublish Message [plant/line1/temperature] QoS 1
9Broker → ClientPublish Ack (id matches)
Publish/Ack cycle repeats
NClient → BrokerPing Request (keep-alive)
N+1Broker → ClientPing Response

Key signs of healthy communication:

  • CONNACK return code = 0 (Connection Accepted)
  • Every QoS 1 PUBLISH has a matching PUBACK
  • PINGREQ/PINGRESP pairs appear at the keep-alive interval
  • No TCP retransmissions
  • No DISCONNECT with error reason codes

7. Diagnosing Connection Failures

Filter: mqtt.msgtype == 2 (CONNACK packets)

CONNACK Return Codes (MQTT v3.1.1)

CodeMeaningCommon Cause
0Connection AcceptedOK
1Unacceptable Protocol VersionClient uses MQTT v3.1 but broker requires v3.1.1 or v5.0
2Identifier RejectedClient ID is empty, too long, or contains invalid characters
3Server UnavailableBroker is starting up or overloaded
4Bad User Name or PasswordWrong credentials
5Not AuthorizedClient not allowed to connect (ACL rejection)

Filter for failures only: mqtt.conack.val != 0

No CONNACK at All

If the client sends CONNECT but receives no CONNACK:

What You SeeCauseFix
TCP SYN, no SYN-ACKBroker is down or port 1883 is blockedCheck broker status. Check firewall.
TCP connected, CONNECT sent, no CONNACKBroker received the CONNECT but did not respondBroker overloaded, or CONNECT packet malformed. Check broker logs.
TCP RST after CONNECTBroker rejected the TCP connectionMax connections exceeded. Check broker configuration.

8. Diagnosing Publish and Subscribe Problems

No Messages Received After Subscribing

Filter: mqtt.msgtype == 8 || mqtt.msgtype == 9 (SUBSCRIBE + SUBACK)

What to CheckWhat It Means
SUBSCRIBE packet shows the correct topic filterIf the topic is wrong, no messages match
SUBACK return code = 0, 1, or 2Subscription accepted at QoS 0, 1, or 2
SUBACK return code = 128Subscription rejected — broker denied the subscription

If SUBACK shows success but no PUBLISH messages arrive, the problem is on the publisher side — no device is publishing to that topic.

Message Payload is Empty or Wrong

Filter: mqtt.msgtype == 3 && mqtt.topic contains "your/topic"

Click the PUBLISH packet and check:

  • mqtt.msg — raw payload bytes
  • mqtt.msg_text — payload as readable text (Wireshark 3.2+)

If the payload is JSON, Wireshark shows it as text. If it is binary (Sparkplug B protobuf, for example), you will see raw bytes.

9. Diagnosing QoS and Message Delivery Issues

MQTT has three QoS levels:

QoSDeliveryWireshark Packet Sequence
0At most once (fire and forget)PUBLISH only — no ACK
1At least once (acknowledged)PUBLISH → PUBACK
2Exactly once (four-step handshake)PUBLISH → PUBREC → PUBREL → PUBCOMP

Diagnosing QoS 1 Problems

Filter: mqtt.msgtype == 3 && mqtt.qos == 1

Then check: does every PUBLISH have a matching PUBACK with the same mqtt.msgid?

If PUBACK is missing, the broker did not acknowledge the message. The client will retransmit with the DUP flag set.

Filter for retransmitted messages: mqtt.dupflag == 1

Diagnosing QoS 2 Problems

Filter: mqtt.msgtype == 5 || mqtt.msgtype == 6 || mqtt.msgtype == 7

The four-step handshake must complete fully. If any step is missing, the message delivery is incomplete.

10. Diagnosing Keep-Alive and Disconnect Problems

Keep-Alive

The client sends a PINGREQ at the keep-alive interval. The broker responds with PINGRESP. If the broker does not receive any packet within 1.5× the keep-alive time, it closes the connection.

Filter: mqtt.msgtype == 12 || mqtt.msgtype == 13

ProblemWhat You SeeFix
Client disconnects unexpectedlyNo PINGREQ sent before broker times outClient is too busy or network latency is too high. Increase keep-alive.
Broker drops the connectionTCP RST or FIN after a period of no MQTT packetsClient keep-alive is too long. Reduce it, or ensure PINGREQ is sent on time.

To see the configured keep-alive: mqtt.kalive in the CONNECT packet.

Unclean Disconnects

A clean disconnect shows DISCONNECT (msgtype 14) followed by TCP FIN. If the client crashes or loses network, you see only TCP RST or timeout — no DISCONNECT packet. The broker then publishes the Last Will message (if configured).

11. Diagnosing Last Will and Testament (LWT)

The LWT is configured in the CONNECT packet. If the client disconnects without sending DISCONNECT, the broker publishes the Will message.

Filter: mqtt.conflag.willflag == 1

Check the CONNECT packet for:

  • mqtt.conflag.willflag — Will Flag is set
  • mqtt.willtopic — the topic the Will message will be published to
  • mqtt.willmsg — the Will message payload
  • mqtt.conflag.qos — QoS level for the Will message
  • mqtt.conflag.retain — whether the Will message is retained

If LWT is not working, verify that the Will Flag is set in the CONNECT packet. If it is missing, the client is not configuring LWT.

12. MQTT over TLS (Port 8883)

MQTT over TLS on port 8883 is encrypted. Wireshark shows it as TLS, not MQTT.

To decode it:

Option 1: Capture Before Encryption

If you have access to the MQTT client or broker, capture on the loopback interface (localhost) where traffic is unencrypted.

Option 2: Use Pre-Master Secret Log

If the client supports it (e.g., Python paho-mqtt with SSL), export the TLS pre-master secret key log and load it in Wireshark:

  1. Set the environment variable: SSLKEYLOGFILE=/path/to/keylog.txt
  2. In Wireshark: Edit → Preferences → Protocols → TLS → (Pre)-Master-Secret log filename → point to the keylog file
  3. Wireshark now decrypts TLS and shows MQTT inside

Option 3: Disable TLS for Debugging

Temporarily switch the broker to port 1883 (unencrypted) for troubleshooting. Do not leave this in production.

13. MQTT in Industrial Systems: Sparkplug B

Sparkplug B is an industrial MQTT specification by the Eclipse Foundation. It standardizes:

  • Topic namespace: spBv1.0/GroupID/MSGTYPE/EdgeNodeID/DeviceID
  • Message types: NBIRTH, NDEATH, DBIRTH, DDEATH, NDATA, DDATA, NCMD, DCMD
  • Payload encoding: Protocol Buffers (protobuf) — binary, not JSON

In Wireshark, Sparkplug B PUBLISH messages show:

  • Topic: spBv1.0/Plant1/DDATA/Gateway01/PLC1
  • Payload: binary protobuf (not human-readable without decoding)

Filter for Sparkplug topics:

mqtt.topic contains "spBv1.0"

Filter for specific message types:

mqtt.topic contains "NBIRTH"
mqtt.topic contains "DDATA"
mqtt.topic contains "DCMD"

To decode the protobuf payload, export the raw bytes from Wireshark and use a Sparkplug B decoder tool or a protobuf parser.

14. Useful Wireshark Columns for MQTT Analysis

Column TitleTypeField Name
Message TypeCustommqtt.msgtype
TopicCustommqtt.topic
Client IDCustommqtt.clientid
QoSCustommqtt.qos
Message IDCustommqtt.msgid
Payload (text)Custommqtt.msg_text
Delta TimeCustomframe.time_delta_displayed

15. Common MQTT Problems and What They Look Like in Wireshark

ProblemWireshark SymptomFilter
Broker offlineTCP SYN with no SYN-ACKtcp.flags.syn == 1 && tcp.port == 1883
Bad credentialsCONNACK return code 4 or 5mqtt.conack.val == 4 || mqtt.conack.val == 5
Client ID rejectedCONNACK return code 2mqtt.conack.val == 2
Subscription deniedSUBACK return code 128mqtt.suback.return_code == 128
Messages not deliveredPUBLISH sent but no PUBACKmqtt.msgtype == 3 && mqtt.qos == 1 — then check for matching PUBACK
Duplicate messagesDUP flag set on PUBLISHmqtt.dupflag == 1
Client drops unexpectedlyNo DISCONNECT before TCP RST/FINmqtt.msgtype == 14 — if absent before TCP close
Keep-alive timeoutNo PINGREQ within keep-alive intervalmqtt.msgtype == 12 — check timing vs mqtt.kalive
LWT not configuredCONNECT without Will Flagmqtt.conflag.willflag == 0
Payload encoding wrongPayload shows binary instead of textCheck mqtt.msg vs mqtt.msg_text — may be protobuf or binary format

Summary

Wireshark decodes every MQTT message type — CONNECT, PUBLISH, SUBSCRIBE, PINGREQ, DISCONNECT, and all QoS handshake packets.

The key things to remember:

  • MQTT runs on TCP port 1883 (unencrypted) and 8883 (TLS)
  • Use mqtt as the main display filter
  • Use mqtt.msgtype to filter by message type (3=PUBLISH, 1=CONNECT, 12=PINGREQ)
  • Use mqtt.topic contains "keyword" to filter by topic name
  • Use mqtt.conack.val != 0 to find failed connections
  • Use mqtt.dupflag == 1 to find retransmitted messages
  • Use mqtt.conflag.willflag to check if LWT is configured
  • For TLS traffic on port 8883, load the pre-master secret key log to decrypt
  • For Sparkplug B, filter with mqtt.topic contains "spBv1.0" — payload is protobuf
Author: Zakaria El Intissar

I'm an automation and industrial computing engineer with 12 years of experience in power system automation, SCADA communication protocols, and electrical protection. I build tools and write guides for Modbus, DNP3, IEC 101/103/104, and IEC 61850 on ScadaProtocols.com to help engineers decode, analyze, and troubleshoot real industrial communication systems.

Leave a Reply

Your email address will not be published. Required fields are marked *