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_pubandmosquitto_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.
Is it legal to capture MQTT traffic?
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.



