MQTT Security

MQTT Wireshark Tutorial: Capture and Analyze MQTT Traffic

Capture your own MQTT traffic with Wireshark, read every packet field on port 1883, and see exactly what TLS on port 8883 protects, using the free broker.connectmq.com test broker.

MQTT Wireshark capture showing decoded CONNECT and PUBLISH packets next to encrypted TLS records on port 8883
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

An MQTT Wireshark capture shows you exactly what your client sends to the broker, field by field. In this tutorial you will capture your own traffic to the free broker.connectmq.com test broker on port 1883, decode CONNECT, SUBSCRIBE and PUBLISH packets, and then repeat the test on TLS port 8883 to see what encryption hides. It is the fastest way to debug connection problems and to prove to yourself why production traffic must use TLS.

Only capture traffic on networks and devices you own or are authorised to monitor.

What You Need

  • Wireshark 3.x or 4.x from the official site, with capture permissions on your machine.
  • The Mosquitto command-line clients (mosquitto_pub and mosquitto_sub).
  • Optionally Python 3 with paho-mqtt 2.x for the TLS decryption step.
  • A unique topic prefix, for example connectmq/demo/ws-4821/.

The public broker is open to everyone, so publish only test data. The free public MQTT broker article lists its limits.

Step 1: Start a Capture With a Port Filter

Open Wireshark, pick the network interface you use for internet access, and enter a capture filter so you only record MQTT traffic:

tcp port 1883 or tcp port 8883

Start the capture. Wireshark recognises MQTT on port 1883 automatically and applies its MQTT dissector.

Step 2: Generate Some Plain MQTT Traffic

In one terminal, subscribe:

mosquitto_sub -h broker.connectmq.com -p 1883 -i ws-sub-4821 -V mqttv5 \
  -t 'connectmq/demo/ws-4821/#' -v

In a second terminal, publish a retained and a normal message:

mosquitto_pub -h broker.connectmq.com -p 1883 -i ws-pub-4821 -V mqttv5 \
  -t 'connectmq/demo/ws-4821/temp' -m '{"celsius":21.7}' -q 1

mosquitto_pub -h broker.connectmq.com -p 1883 -i ws-pub-4821 -V mqttv5 \
  -t 'connectmq/demo/ws-4821/status' -m 'online' -r

Stop the subscriber with Ctrl+C and stop the capture.

Step 3: Apply MQTT Display Filters

Type a display filter in the bar at the top. These are the most useful ones:

Display filter Shows
mqtt All decoded MQTT packets
mqtt.msgtype == 1 CONNECT
mqtt.msgtype == 2 CONNACK
mqtt.msgtype == 3 PUBLISH
mqtt.msgtype == 8 SUBSCRIBE
mqtt.msgtype == 12 or mqtt.msgtype == 13 PINGREQ and PINGRESP
mqtt.msgtype == 14 DISCONNECT
mqtt.topic contains "ws-4821" Packets for your topic prefix
mqtt.clientid == "ws-pub-4821" CONNECT from a specific client
tls Encrypted traffic, typically on 8883

Field names can differ slightly between Wireshark versions. If a filter is rejected, expand a packet and right-click a field, then choose "Apply as Filter" to get the exact name.

Step 4: Read the Decoded Packets

CONNECT

Select a CONNECT packet and expand "MQ Telemetry Transport Protocol". You will see:

  • Protocol name and version (MQTT, version 5 or 4 for 3.1.1).
  • Connect flags: clean start, will flag, username and password flags.
  • Keep alive in seconds.
  • Properties (MQTT 5), such as session expiry interval.
  • Client ID, here ws-pub-4821.

If a client sent a username and password over port 1883, both would be visible here in plain text. That single observation is the strongest argument for TLS you will ever need.

CONNACK

The CONNACK shows the reason code (0x00 means success) and, for MQTT 5, server properties such as maximum packet size, receive maximum, whether retained messages and wildcard subscriptions are available, and the maximum QoS. Reading these is a quick way to understand a broker's limits.

SUBSCRIBE and SUBACK

The SUBSCRIBE packet lists topic filters with options. The SUBACK returns one reason code per filter. A code of 0x80 or higher means the subscription was refused, which is easy to miss in application logs but obvious in Wireshark.

PUBLISH

Each PUBLISH shows the topic, QoS, retain flag, packet identifier for QoS 1 and 2, properties and the raw payload. Your {"celsius":21.7} message is readable in the packet bytes pane. The QoS 1 publish is followed by a PUBACK from the broker with the same packet identifier. See MQTT QoS levels explained for what each exchange means.

Step 5: Repeat the Test Over TLS on Port 8883

Start a new capture with the same filter and repeat the publish, this time using TLS:

mosquitto_pub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
  -i ws-pub-tls-4821 -V mqttv5 \
  -t 'connectmq/demo/ws-4821/temp' -m '{"celsius":22.1}' -q 1

On Windows or macOS, point --cafile at a CA bundle instead of --capath. ConnectMQ uses a Let's Encrypt certificate, which standard CA bundles trust.

Apply the display filter tls. Now you see:

  • A TLS handshake: ClientHello, ServerHello and, depending on the version, certificate messages.
  • The Server Name Indication (broker.connectmq.com) in the ClientHello, which is not encrypted.
  • "Application Data" records with no visible topic, client ID or payload.

An observer on the network can still see that you talked to the broker, when, and roughly how much data you sent. They cannot see credentials, topics or message content. That is the protection TLS gives you, and the MQTT TLS configuration guide explains how to set it up on every client.

Step 6: Decrypt Your Own TLS Traffic for Debugging

Sometimes you need to inspect TLS traffic from your own client during development. Wireshark can decrypt TLS if the client writes its session keys to a key log file. Python's ssl module supports this:

import ssl
import time
import paho.mqtt.client as mqtt

ctx = ssl.create_default_context()
ctx.keylog_filename = "tls-keys.log"  # development only, never in production

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="ws-py-tls-4821",
                     protocol=mqtt.MQTTv5)
client.tls_set_context(ctx)

def on_connect(c, userdata, flags, reason_code, properties):
    print("connected:", reason_code)
    c.publish("connectmq/demo/ws-4821/debug", "decrypt me", qos=1)

client.on_connect = on_connect
client.connect("broker.connectmq.com", 8883, keepalive=30)
client.loop_start()
time.sleep(3)
client.loop_stop()
client.disconnect()

In Wireshark, go to Edit > Preferences > Protocols > TLS and set "(Pre)-Master-Secret log filename" to the tls-keys.log file. Because Wireshark does not know that port 8883 carries MQTT, right-click a TLS packet, choose "Decode As..." and set port 8883 to MQTT. The decrypted packets now show the same fields you saw on 1883.

Delete the key log file afterwards. Anyone with it can decrypt that capture.

Troubleshooting With Wireshark

Symptom in capture Likely cause
SYN sent, no SYN-ACK Firewall blocking the port or wrong hostname
TCP connects, client sends CONNECT, broker closes immediately Protocol violation, empty client ID or invalid credentials
CONNACK with reason 0x86 or 0x87 Bad username/password or not authorised
CONNACK with 0x85 Client identifier not valid
TLS alert "unknown CA" or "bad certificate" Client does not trust the certificate chain
PINGREQ without PINGRESP, then reset Network drops idle connections; reduce keep alive
DISCONNECT with 0x97 Quota exceeded on the broker
Many CONNECT packets seconds apart Reconnect loop, often from a duplicate client ID

The duplicate client ID case is particularly common: two devices with the same ID take turns kicking each other off, and Wireshark shows the pattern instantly.

Taking It to Production

The public broker is for tests. For real data, create a private broker, use the generated username, password and client ID, and connect only over TLS on 8883 or secure WebSockets on 8084. On ConnectMQ, private brokers also include tenant isolation, quotas, flood protection and IP blocking after repeated failed logins. Wireshark remains useful there: capturing on your side confirms that nothing leaves your device unencrypted. To understand what else can go wrong on unprotected brokers, read about exposed MQTT brokers.

Get Started with ConnectMQ

Try the captures above against broker.connectmq.com right now, then create a private broker on the free Serverless plan at app.connectmq.com with no credit card. Your client code needs only a hostname, credentials and port 8883 to move from test to a managed MQTT broker. For general hardening tips, see MQTT security best practices.

Frequently Asked Questions

Why does Wireshark not show MQTT on port 8883?

Traffic on 8883 is encrypted with TLS, so Wireshark only sees TLS records. You can decrypt your own sessions with a key log file and then use "Decode As" to apply the MQTT dissector.

What is the Wireshark filter for MQTT?

Use the display filter mqtt for all decoded packets, or mqtt.msgtype == 3 for PUBLISH packets only. A capture filter of tcp port 1883 limits recording to plain MQTT.

Can Wireshark see MQTT over WebSockets?

Yes, on an unencrypted WebSocket port Wireshark decodes the WebSocket frames and can apply the MQTT dissector to their payload. Secure WebSockets on 8084 are encrypted like port 8883.

Capturing traffic on your own devices and networks for debugging is normal practice. Capturing other people's traffic without authorisation is not, so limit captures to systems you own or are permitted to monitor.

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.