
抓包看懂MQTTWireshark过滤规则CONNECT报文逐字段入门一、为什么抓包是排查的终极手段做 MQTT 这些年我最大的体会是日志会说谎抓包不会。客户端报连接被拒日志可能只给你一句笼统的 error但只要把包抓下来CONNECT 报文里的 Client ID、Clean Session、用户名密码、Keep Alive全是一清二楚的字节问题出在哪一眼就能看出来。这一篇带你入门 MQTT 抓包先学会 Wireshark 的过滤规则再逐字段拆一个 CONNECT 报文。这篇是热身下一篇第 6 篇我会带你逐字节拆 MQTT 固定头把DUP/QoS/RETAIN那几个标志位算给你看——那是全网少见的硬核内容也是收藏率最高的硬通货。二、先分清捕获过滤 vs 显示过滤Wireshark 有两种过滤新手最容易混淆一句话说清类型作用时机语法例子捕获过滤Capture Filter抓包时就过滤没匹配的直接不存BPF 语法tcp port 1883显示过滤Display Filter抓完后再筛选显示不影响已抓的数据Wireshark 表达式mqtt实操建议MQTT 默认在 1883 端口流量不算大捕获过滤直接写tcp port 1883即可避免抓到一堆无关流量。抓完之后再用显示过滤精准定位。三、开始抓包三步走打开 Wireshark选中你正在用的网卡本机 loopback 通常是Loopback: lo0。捕获过滤填tcp port 1883点开始抓包。用上一篇装好的 MQTTX 连一次 EMQX连mqtt://localhost:1883再断开。回到 Wireshark停抓包你会看到CONNECT → CONNACK的一来一回。坑点抓本机回环localhost流量时macOS 上要选Loopback接口Windows 上可能要用Npcap的回环支持如果抓不到确认是不是选了错误的网卡比如选了 Wi-Fi 但流量走的是 loopback。四、 可拿走资产MQTT 显示过滤速查表在 Wireshark 顶部的显示过滤框里输入mqtt.前缀有自动补全善用目标显示过滤表达式所有 MQTT 报文mqtt只看 CONNECTmqtt.msgtype 1只看 CONNACKmqtt.msgtype 2只看 PUBLISHmqtt.msgtype 3只看心跳 PINGREQmqtt.msgtype 12只看断开 DISCONNECTmqtt.msgtype 14某主题的消息mqtt.topic iot/dev/10086/temp主题按前缀匹配mqtt.topic contains iot/dev只看 QoS1 的 PUBLISHmqtt.qos 1只看带 RETAIN 的消息mqtt.retain 1某 Client ID 的连接mqtt.clientid demo-client连接被拒绝的报文mqtt.conack.val 0组合某端口 某主题tcp.port 1883 mqtt.topic contains tempMQTT 报文类型对照表mqtt.msgtype取值建议收藏msgtype报文作用1CONNECT客户端连接请求2CONNACK服务端确认连接3PUBLISH发布消息4PUBACKQoS1 确认第 3 篇的握手5PUBRECQoS2 第一步确认6PUBRELQoS2 第二步7PUBCOMPQoS2 完成8SUBSCRIBE订阅请求9SUBACK订阅确认10UNSUBSCRIBE取消订阅11UNSUBACK取消订阅确认12PINGREQ心跳请求保活13PINGRESP心跳响应14DISCONNECT断开连接15AUTH增强认证仅 MQTT 5.0五、逐字段拆解 CONNECT 报文在 Wireshark 里点开第一条 CONNECT你会看到它被解析成三层结构。下面用一个真实的最小 CONNECT 报文逐字段讲5.1 看一个真实的十六进制下面是一个最小化的 MQTT 3.1.1 CONNECT 报文Client ID 为demo-clientClean SessionKeep Alive 60 秒10 17 ← 固定头报文类型CONNECT(0x10)剩余长度23 字节(0x17) 00 04 4D 51 54 54 ← 可变头协议名 MQTT长度 4 4 字节 04 ← 可变头协议级别 0x04 MQTT 3.1.1 02 ← 可变头连接标志见下文逐位拆解 00 3C ← 可变头Keep Alive 60 秒 00 0B 64 65 6D 6F 2D 63 6C 69 65 6E 74 ← 载荷Client ID demo-client对照着这个十六进制逐字段看5.2 固定头Fixed Header—— 先认识它第 6 篇拆透第 1 个字节0x10高 4 位0001表示报文类型 CONNECT1低 4 位0000是标志位CONNECT 类型固定为 0。第 2 个字节0x17 23表示剩余长度。这里就是后面所有字节的总长23 字节。剩余长度用的是变长编码这个逐字节拆固定头的活我留到第 6 篇那里会给你一张图解。5.3 可变头Variable Header字段字节本例值含义Protocol Name00 04 4D 51 54 54“MQTT”协议名长度前缀 “MQTT”3.1 时代是 “MQIsdp”Protocol Level0444 MQTT 3.1.15 MQTT 5.005Connect Flags02见下1 字节8 个标志位Keep Alive00 3C60 秒保活间隔超时未通信服务端会判定掉线5.4 Connect Flags1 个字节 8 个开关重点0x02展开成二进制是0000 0010从高到低 8 位各司其职位名称本例值含义7Username Flag0是否带用户名6Password Flag0是否带密码5Will Retain0遗嘱消息是否保留4-3Will QoS00遗嘱消息的 QoS2Will Flag0是否设置遗嘱消息1Clean Session3.1.1/ Clean Start5.01会话是否从干净状态开始0Reserved0保留位必须为 0本例0x02只有位 1 为 1意思是开启 Clean Session不带遗嘱、不带用户名密码。5.5 载荷Payload字段本例值说明Client ID“demo-client”客户端唯一标识长度前缀00 0B 11 字节Will Topic / Will Message无仅当 Will Flag1 时才出现Username / Password无仅当对应 Flag1 时才出现5.6 遗嘱Will字段三个字节决定设备死没死遗嘱是 MQTT 最巧妙的机制之一值得单拎出来说。当设备异常掉线没发 DISCONNECT 就断网了Broker 会替它发布一条遗嘱消息告诉其他人这台设备下线了。CONNECT 里的Will Flag / Will QoS / Will Retain三个标志位 载荷里的Will Topic / Will Message就是这套机制的开关。用它来做设备在线状态比定时轮询设备在不在优雅得多第 8 篇会专门讲遗嘱、保留消息、会话保持这三个最易混淆的机制。六、CONNACK服务端回的那一句准不准CONNECT 之后服务端会回一个 CONNACK。排查连接被拒就看这个报文的返回码返回码3.1.1含义常见原因0x00接受连接正常0x01不支持的协议版本客户端版本和 Broker 不匹配0x02标识符被拒Client ID 非法/被占用0x03服务不可用Broker 忙/资源不足0x04用户名或密码错误认证失败0x05未授权认证通过但无权限ACL在 Wireshark 里用显示过滤mqtt.conack.val 0能一次性把所有被拒的连接捞出来再逐个看mqtt.conack.val是几。这套组合拳比翻一万行日志快得多。MQTT 5.0 的 CONNACK 换成了更细的 Reason Code0x80起为失败后面讲 MQTT 5 的篇章会展开。七、写在最后恭喜你到了这一步你已经能从抓包这个上帝视角看懂 MQTT 的连接过程了——这是从会用走向懂协议的第一道门槛。下一篇文章我们把视角再往下沉一层逐字节拆解 MQTT 固定头——报文类型、剩余长度的变长编码、DUP / QoS / RETAIN三个标志位到底是怎么在 1 个字节里被压缩的。我会用二进制手算的方式带你走一遍看完你会发现原来 MQTT 的轻量真的是省到了字节级别。 评论区提问你用 Wireshark 抓过 MQTT 吗有没有遇到抓不到本地流量或解析不出来的情况留言说说我在后面的 L2 深度篇会补一个MQTT 抓包进阶的专题。