MQTT 实战与排错 — 抓包、mosquitto 命令与故障排查
MQTT 实战:Wireshark 抓包过滤式、mosquitto_pub/sub 实操、Broker 配置、常见故障与排错、与 CoAP/AMQP 对比、速查表与面试题 / 应用层(物联网)/ TCP 1883、8883 / OASIS MQTT v3.1.1、v5.0
这篇你能学到
- 怎么用 Wireshark
mqtt过滤式抓包看 CONNECT/CONNACK 返回码、Topic、QoS、Retain 位,以及mosquitto_pub/sub把发布/订阅跑通。 - 怎么配 Mosquitto/EMQX Broker(端口、TLS、密码文件、ACL、桥接),以及常见客户端库与桥接用法。
- 遇到连接被拒、收不到消息、遗嘱不触发、频繁掉线、TLS 失败、消息丢失等 9 类问题时先记结论再按"网络→协议→应用→Broker"四层排查,以及与 CoAP/AMQP/HTTP 的选型对比。
抓包观察(Wireshark 过滤式)
MQTT 走 TCP,Wireshark 用 mqtt 显示过滤器解析;若走 WebSocket 则用 mqtt 仍可读(Wireshark 会解 WebSocket 内的 MQTT 帧)。下面这张表是抓包时的"检索目录":
| 目的 | Wireshark / tshark 过滤式 |
|---|---|
| 所有 MQTT 流量 | mqtt |
| 指定 TCP 端口 | tcp.port == 1883 或 tcp.port == 8883 |
| 仅 CONNECT / CONNACK | `mqtt.msgtype == 1 |
| 仅 PUBLISH | mqtt.msgtype == 3 |
| 指定主题 | mqtt.topic contains "factory/line1" |
| 指定 QoS | mqtt.qos == 2 |
| 保留消息 | mqtt.retain == 1 |
| 遗嘱相关 | mqtt.willflag == 1(CONNECT 中) |
| 连接用户名 | mqtt.username / mqtt.password(明文凭据,注意安全) |
| 协议版本 | 在 CONNECT 可变头看 Protocol Level(4=v3.1.1, 5=v5.0) |
| 抓包命令(tshark) | tshark -i eth0 -Y "mqtt" -T fields -e mqtt.topic -e mqtt.qos |
| 命令行抓包 | tcpdump -i eth0 -w mqtt.pcap 'tcp port 1883' 后用 Wireshark 打开 |
提示:8883(TLS)下 Wireshark 默认看不到明文 MQTT,需在
编辑 → 首选项 → Protocols → TLS配置 (Pre)-Master-Secret 日志文件 或导入私钥解密后才能解析 MQTT 层。
mosquitto 自带客户端快速验证:下面 4 条覆盖"订阅、发保留消息、带凭据+遗嘱、看系统主题"四个最常见动作,用来确认 Broker 是否正常工作。
| |
常用命令 / 配置
1. Eclipse Mosquitto Broker 配置(mosquitto.conf)
下面这份配置同时做了"禁匿名 + 开 TLS + 配密码文件 + 持久化 + ACL"五件事,是生产可用的最小骨架:
| |
acl.conf 示例:
2. EMQX(云原生 Broker,常用命令)
3. 客户端库(开发常用)
| 语言 | 库 |
|---|---|
| Python | paho-mqtt(import paho.mqtt.client as mqtt) |
| Go | eclipse/paho.mqtt.golang |
| Node.js | mqtt(npm 包) |
| C/C++ | paho.mqtt.c |
| Java | Eclipse Paho Java / HiveMQ MQTT Client |
| 嵌入式 | esp-mqtt(ESP32)、nanomq(边缘 MQTT-SN 桥接) |
4. 桥接(Broker ↔ Broker)
下面这段把本地 factory/# 转发到云端 Broker,是"边缘↔云"打通的标准做法:
常见故障与排错
故障 1:连接被拒(CONNACK 返回码非 0)
先记住结论:连接被拒先看 CONNACK 的返回码/原因码,几乎都指向"版本不对、ClientID 冲突、凭据错、未授权"四选一。v3.1.1 返回码:1=协议版本不支持、2=客户端 ID 不合格、3=服务器不可用、4=用户名/密码错、5=未授权。
| 可能原因 | 排查与处置 |
|---|---|
| v3.1.1 返回码:1=协议版本不支持、2=客户端 ID 不合格、3=服务器不可用、4=用户名/密码错、5=未授权 | 看 CONNACK 返回码;v5 看原因码;核对 Protocol Level(4=v3.1.1,5=v5)、ClientID 唯一性、凭据、ACL |
故障 2:订阅收不到消息
先记住结论:收不到消息先怀疑"通配符层数写错"或"发布/订阅 QoS 取小后没达到预期",再查 Retained 是否漏设导致晚订阅者错过。Wireshark 抓 mqtt.topic 一比对就知道。
| 可能原因 | 排查与处置 |
|---|---|
主题通配符写错(+/# 层数不符)、发布与订阅 QoS 取小后低于预期、Retained 没设导致晚订阅者错过 | Wireshark 抓 mqtt.topic 比对;确认订阅端 SUBACK 授予 QoS;用 mosquitto_sub -v 验证;关键状态用 RETAIN=1 |
故障 3:QoS 2 消息重复/乱序
先记住结论:QoS2 的"去重"靠报文标识符(PacketId),重复/乱序通常是客户端没按 PacketId 维护未完成表——Broker 端一般已处理好,重点查客户端实现。
| 可能原因 | 排查与处置 |
|---|---|
| 网络重传导致 PUBREC/PUBREL 重发;客户端未正确按 Packet Identifier 去重 | 确保客户端按 PacketId 维护"未完成 QoS2"表;Broker 端通常已处理,重点查客户端实现 |
故障 4:遗嘱不触发
先记住结论:遗嘱只在"异常断线/心跳超时"时触发,优雅 DISCONNECT 不会发——调试必须拔网线/断电,别指望正常退出能看到;另外确认遗嘱 Topic 被 ACL 放行。
| 可能原因 | 排查与处置 |
|---|---|
| 客户端是正常 DISCONNECT 断开(遗嘱不会发);或 Broker 在 Keep Alive 超时前没检测到断线 | 异常断网(拔网线/断电)才触发;确认 Keep Alive 合理;遗嘱 Topic 是否被 ACL 允许发布 |
故障 5:频繁掉线 / 假死
先记住结论:频繁掉线多半是 Keep Alive 太大发现不了断网,或 NAT/防火墙把空闲长连接回收了——缩短 Keep Alive、定时 PINGREQ、防火墙侧开长连接保活。
| 可能原因 | 排查与处置 |
|---|---|
| Keep Alive 过大导致断网很久才被发现;NAT/防火墙空闲连接被回收(如 5 分钟无包即踢) | 缩短 Keep Alive(如 30~60s);客户端定时 PINGREQ;防火墙侧设长连接保活;移动网络建议更小 Keep Alive |
故障 6:TLS 连接失败
先记住结论:8883 握手失败先验证书链——SNI/域名不符、过期、CA 没下发客户端、单向/双向配置不一致,是四类最常见原因。
| 可能原因 | 排查与处置 |
|---|---|
| 证书链不完整、SNI/域名不符、证书过期、8883 端口被中间盒拦截 | openssl s_client -connect host:8883 验证证书;检查 require_certificate 双向/单向配置;确认 CA 已下发客户端 |
故障 7:Broker CPU/内存飙升
先记住结论:Broker 资源飙升通常是 $SYS 轮询过多、巨型 Retained、订阅膨胀、Receive Maximum 没设导致窗口打满——限 Receive Maximum、清 stale 会话、监控 $SYS。
| 可能原因 | 排查与处置 |
|---|---|
大量 $SYS 轮询、巨型 Retained、订阅膨胀、未设 Receive Maximum 导致窗口打满 | 限制 Receive Maximum(v5)、定期清理 stale 会话、监控 $SYS/broker/...;EMQX 用规则引擎削峰 |
故障 8:消息丢失(以为 QoS 足够)
先记住结论:“感觉 QoS 够却丢消息"几乎都是"发布用了 QoS0"或"桥接转发时被降级”——关键数据发布必须 QoS1/2,桥接两端 QoS 要协商一致。
| 可能原因 | 排查与处置 |
|---|---|
| 发布用 QoS0 却期望不丢;或 Bridge 转发时降级 | 关键数据发布用 QoS1/2;桥接两端协商一致 QoS;确认 topic ... out QoS 配置 |
故障 9:安全告警:明文 1883 暴露公网
先记住结论:明文 1883 出公网 = 凭据和消息裸奔,等于敞开大门——必须关匿名、上 TLS、配 ACL、限来源 IP,必要时加 JWT/认证插件。
| 可能原因 | 排查与处置 |
|---|---|
| 未禁匿名、无 TLS、无 ACL | 关闭 allow_anonymous、启用 8883 TLS、配置 ACL、用安全组限制来源 IP;必要时加 mosquitto_auth_plugin/JWT |
排错方法论(由下而上)
先记住结论:MQTT 排错按"网络 → 协议 → 应用 → Broker"四层从下往上查,绝大多数问题在前两层就能定位。
- 网络层:
tcpdump port 1883确认 TCP 三次握手是否成功;telnet host 1883验证端口可达。 - 协议层:Wireshark 看 CONNECT/CONNACK 返回码、SUBACK 授予 QoS、PUBLISH 的 Topic/QoS/Retain 位。
- 应用层:核对 ClientID 唯一、遗嘱/保留/会话语义是否符合预期、ACL 是否放行。
- Broker 侧:查
$SYS/broker/指标、日志(mosquitto -v前台 verbose;EMQXemqx_ctl log)。
与其他协议对比
MQTT vs CoAP vs AMQP
| 维度 | MQTT | CoAP | AMQP |
|---|---|---|---|
| 传输层 | TCP(可靠) | UDP(可选 DTLS) | TCP(可靠,复杂握手) |
| 通信模型 | 发布/订阅(Broker) | 请求/响应(REST 风格) | 队列 + 发布/订阅(Broker/Exchange) |
| 头部开销 | 极小(≥2B) | 极小(4B 固定头) | 较大(协议帧复杂) |
| 适用网络 | 弱网/移动/长连接 | 极受限、无 TCP 的传感网 | 企业内网、金融级可靠 |
| QoS | 0/1/2 三级 | 可确认/不可确认(轻) | 事务级(at-least/at-most/exactly) |
| 典型实现 | Mosquitto/EMQX/HiveMQ | Californium/CoAP++ | RabbitMQ/ActiveMQ |
| 一句话 | 海量终端实时遥测 | 类 HTTP 的受限节点 | 企业消息总线 |
与 HTTP 的取舍
- MQTT 优势:长连接低开销、服务端可主动推送(HTTP 需轮询或 WebSocket)、天然一对多广播、弱网友好。
- HTTP 优势:穿透性好(80/443 通用)、生态成熟、无状态易水平扩展、适合偶发请求(如 OTA 固件下载)。实践中常"MQTT 做实时 + HTTP 做配置/升级"。
速查表
| 项目 | 取值 / 说明 |
|---|---|
| 默认端口 | 1883(明文)/ 8883(TLS)/ 80·443(WebSocket) |
| 协议级别字节 | 4 = v3.1.1;5 = v5.0 |
| QoS 含义 | 0 至多一次 / 1 至少一次 / 2 恰好一次 |
| 通配符 | + 单层、# 多层(末尾)、$ 系统主题 |
| 控制报文数 | 14 种(v3.1.1)+ AUTH(v5)= 15 |
| 最小报文 | 固定头 2 字节(如 PINGREQ/PINGRESP) |
| 剩余长度上限 | 4 字节变长编码 → 268,435,455 B(≈256 MB) |
| 心跳 | Keep Alive 秒;超时判定 1.5×KeepAlive |
| 保留消息清除 | 发 RETAIN=1 + 空载荷 |
| 常见 Broker | Mosquitto、EMQX、HiveMQ、VerneMQ、RabbitMQ(插件) |
常见面试题
- MQTT 为什么适合物联网? 头部小、长连接低功耗、发布订阅解耦多对多、弱网友好、QoS 可选。
- QoS 0/1/2 的区别? 至多一次 / 至少一次(PUBACK)/ 恰好一次(PUBREC+PUBREL+PUBCOMP 四次握手)。
- 发布与订阅 QoS 不一致怎么办? 取较小值;Broker 按订阅者请求的 QoS 转发。
- Retained 与 Last Will 的区别? Retained 是"主题最新值留存给新订阅者";Will 是"异常断线时代发的遗言"。
- Clean Session 的作用? 控制断线后订阅关系与离线消息是否保留(v5 由 Clean Start + Session Expiry 取代)。
+和#的区别?+匹配单层、#匹配其后多层且必须末尾。- 遗嘱什么时候触发、什么时候不触发? 异常断线/心跳超时触发;正常 DISCONNECT 不触发。
- MQTT 与 CoAP / AMQP 怎么选? TCP 长连接遥测选 MQTT;极受限 UDP 节点选 CoAP;企业级可靠消息总线选 AMQP。
- 8883 是什么、为什么需要 TLS? MQTT over SSL/TLS,防止凭据与消息被窃听/篡改,公网必开。
- MQTT 5.0 相比 3.1.1 主要增强? 原因码、Properties、Session Expiry、共享订阅、消息过期、主题别名、增强认证 AUTH、Response Topic 请求/响应模式。