为什么是它

设备上报的程序最容易卡住的地方,不是代码写不出来,是"数据到底走到哪一步了"

典型场景:现场设备接好了,采集程序也在跑,但云平台上什么都看不到。这根链路中间有三方——设备、Broker(消息服务器)、订阅端,而且谁都不报错。你只能猜:设备根本没发?发了但格式不对?Broker 拒收了?还是订阅端的主题写错了?

排这种问题,需要一个能以第三方身份独立接入的工具:它不掺和你的业务代码,自己连上 Broker、自己订阅,看看到底有没有消息过来、内容长什么样。

MQTTX 就是干这个的。它是 EMQX(MQTT Broker 领域最主流的厂商之一)开源的 MQTT 5.0 客户端,Apache-2.0 协议,一套内核三种形态

形态

什么时候用

桌面版(Electron,带界面)

手动调试、盯消息流、配 TLS 证书、看历史

命令行 CLI

写进脚本、服务器上没有图形界面、CI 里做连通性检查

网页版

临时借用别人的电脑,或不想装东西

活跃度用硬指标说话(这些都是查得到的,不是形容词):

指标

数据

最新版本

v1.13.1,发布于 2026-09-20

最近几个版本

v1.13.0(2026-01-23)、v1.12.1(2025-09-30)、v1.12.0(2025-06-25)

许可

Apache-2.0(商用、改造都允许)

仓库

emqx/MQTTX,约 5.0k star,最后提交 2026-09-20

支持平台

Windows / macOS / Linux(含 arm64)

协议支持

MQTT 5.0、3.1.1、3.1

同类工具横向对比,方便你判断该用哪个:

工具

形态

特点与局限

MQTTX

桌面 + CLI + Web

三形态齐全,MQTT 5.0 特性覆盖最全,Apache-2.0

MQTT Explorer

桌面

按主题树浏览全部历史消息非常直观,但没有命令行版本

mosquitto_pub/sub

CLI

轻量,装 mosquitto 就有;功能少,无压测、无载荷格式化

MQTT.fx

桌面

老牌工具,近年更新明显放缓

先用五分钟把 MQTT 搞懂

MQTTX 的界面很直观,但如果不知道协议在做什么,你看到的只是一堆字符串。下面这五件事搞明白,后面所有操作都能对上号。

1. 发布/订阅,不是请求/响应

和 HTTP 最大的区别:发消息的人不认识收消息的人

                    ┌──────────────┐
   设备 ──publish──▶│              │──deliver──▶ 订阅端 A
   (只负责发)       │   Broker     │
                    │  (消息服务器) │──deliver──▶ 订阅端 B
   采集程序 ──────▶ │              │
                    └──────────────┘
                    按"主题"路由,不按地址

三方互不直连,全靠一个中间人(Broker)按主题(Topic)转发。好处是解耦:设备只管往主题上发,谁需要谁自己订阅,加一个订阅方不用改设备一行代码。

2. 主题(Topic):一条用 / 分层的字符串

factory/line1/plc01/temperature
   │      │     │        │
 厂区   产线   设备     数据

订阅时可以用两个通配符:

通配符

含义

例子

+

匹配一层

factory/+/plc01/temperature 匹配任意产线

#

匹配往下所有层

factory/line1/# 匹配 line1 下所有数据

两条硬规则,写错了订阅不会报错,只会静默收不到消息

  • # 只能出现在最后一级factory/#/temperature 是非法主题;

  • + 必须独占一层factory/line+/temperature 也非法。

另外,$ 开头的主题(如 $SYS/)不会被 #+ 开头的订阅匹配到,必须显式订阅 $SYS/#。这是刻意的设计,防止通配符把 Broker 自身的运行指标一并吞掉。

3. QoS:三种投递保证

QoS

语义

代价

0

最多一次,发出去就不管

可能丢,最快

1

至少一次,没收到确认就重发

可能重复,需要业务侧做幂等

2

恰好一次,四次握手

最可靠,最慢

工程上的常见选择:周期性的传感器数据用 0 或 1(丢一条下一周期就补上了),开关指令、计费事件用 1 或 2

4. Retain(保留消息):给每个主题存一份"最新值"

普通消息只在发布的那一刻转发给当时的在线订阅者。加了 Retain 标志后,Broker 会把这条消息存在这个主题上,之后任何新订阅者一连上来就能立刻收到。

它的典型用途是"当前状态"——新上线的监控界面一订阅,马上就能看到设备的最新值,不用傻等下一个上报周期。

一个必须记住的限制:Retain 只保留每个主题的最后一条。它不是历史数据库,想存历史得靠订阅端自己落盘。

5. Will(遗嘱消息):设备"死了"也要说一声

连接时可以预先注册一条遗嘱消息。如果这个客户端异常断开(断网、断电、进程被杀),Broker 会替它把这条消息发出去。

配合 factory/line1/plc01/status 这类主题,就能实现"设备离线自动告警",不需要设备端写任何额外逻辑。

端口和版本

端口

用途

1883

MQTT over TCP(明文,最常用)

8883

MQTT over TLS

8083

MQTT over WebSocket

8084

MQTT over WebSocket Secure

MQTT 3.1.1 和 5.0 的差别,对你日常调试影响最大的是 5.0 新增的能力:原因码(连不上时告诉你为什么,而不是默默断线)、用户属性(在消息头里塞自定义元数据)、会话过期间隔(断线后会话保多久)、共享订阅(多个订阅方负载均衡)、主题别名(省带宽)、消息过期间隔(过期数据自动丢弃)。

MQTTX 默认按 5.0 连接,对不支持的 Broker 用 -V 3.1.1 切回去。

安装

桌面版

平台

方式

命令 / 说明

Windows

winget

winget install --id EMQ.MQTTX

Windows

scoop

scoop install extras/mqttx

Windows

安装包

MQTTX-Setup-1.13.1-x64.exe(GitHub Releases)

macOS

Homebrew

brew install --cask mqttx

macOS

App Store

搜 MQTTX

Linux

Snap

sudo snap install mqttx

Linux

deb / rpm / AppImage

MQTTX_1.13.1_amd64.deb / MQTTX-1.13.1.x86_64.rpm / MQTTX-1.13.1.AppImage

任意

免安装包

Windows 有 MQTTX-1.13.1-x64-win.zip 便携版

命令行 CLI

官方主推独立二进制(就是官网说的 "dependency-free")——从 GitHub Releases 直接下,不用装 Node:

平台

文件名

Windows x64

mqttx-cli-win-x64.exe

Windows arm64

mqttx-cli-win-arm64.exe

Linux x64 / arm64

mqttx-cli-linux-x64 / mqttx-cli-linux-arm64

Alpine

mqttx-cli-alpine-x64 / mqttx-cli-alpine-arm64

macOS

mqttx-cli-macos-x64 / mqttx-cli-macos-arm64

如果你本来就有 Node 环境,用 npm 也行:

npm install -g mqttx-cli@latest
mqttx --version

注意写 @latest 实测遇到过 npm install -g mqttx-cli 装出来是 1.10.1(2024 年的版本),而当时最新已经是 1.13.1——大概率是 registry 镜像或本地缓存的旧元数据导致的。显式写 @latest 就不会踩到。不想折腾就直接下独立二进制。

Docker 里跑(适合服务器上短暂排查):

docker run -it --rm emqx/mqttx-cli pub -t test -h broker.emqx.io -m "hello"

网页版

浏览器打开 mqttx.app,不用安装。适合临时借用别人电脑排查——但连接信息和账号密码是打到对方浏览器里的,敏感环境别用。

一个免费的公共 Broker

不想自己搭 Broker 也能练手,EMQX 提供了公开测试服务器:

Broker: broker.emqx.io
TCP 端口: 1883
SSL 端口: 8883

⚠️ 公开服务器上任何人的消息互相可见,只放测试用的假数据

桌面版:五步上手

界面逻辑和聊天软件很像——左边是"会话列表",中间是"消息流"。

① 新建连接:点左侧栏的 +,填连接表单。

字段

说明

Name

连接名,随便起,只影响显示

Client ID

客户端标识。默认随机生成,同一 Broker 上不要和别的客户端重复

Host

Broker 地址(broker.emqx.io,或你自己服务器的 IP)

Port

默认 1883

Username / Password

Broker 开了认证才需要填

② 连接:点右上角 Connect。状态变成已连接就成功了。

③ 订阅:在订阅区点 New Subscription,填主题(如 factory/#),选 QoS,可以给不同主题配不同颜色方便区分。

④ 发布:在右上发布区填主题、QoS,勾选 Retain 就是保留消息,粘贴载荷后点发送。

⑤ 看消息:中间区域实时滚出收到的消息,每条都能展开看完整内容。

桌面版还有几处值得知道的:

  • 载荷格式:支 Plaintext / JSON / Base64 / Hex 互转。收到一坨乱码时切 Hex 看,往往一眼就认出结构;

  • 多窗口 / 多连接:同时连多个 Broker 或同 Broker 上多个客户端,互不干扰;

  • 脚本:可以对消息跑一段 JavaScript 做加工(v1.4.2 起支持);

  • 流量统计:订阅 $SYS/# 能看到 Broker 的连接数、消息速率等运行指标;

  • TLS 完整支持:CA 证书、自签名证书、双向认证都能配。

CLI 速查表

CLI 是这篇的重点——桌面版会点鼠标就行,CLI 才是能写进脚本、能上服务器的那一半

连接 / 发布 / 订阅

命令

作用

mqttx conn -h <host> -p <port>

建立连接并保持(验证"能不能连上")

mqttx pub -t <topic> -m <msg>

发布一条消息

mqttx sub -t <topic>

订阅并持续接收(Ctrl+C 退出)

mqttx pub -t <topic> -s

从标准输入读消息体(配管道用)

mqttx pub -t <topic> -r

发布保留消息

mqttx sub -t <topic> -q 1

指定 QoS 订阅

mqttx sub -t <topic> -f hex

按 Hex 格式化收到的载荷

常用参数

参数

含义

-h, --hostname

Broker 地址(默认 localhost)

-p, --port

端口(默认 1883)

-t, --topic

主题;可重复,一次订阅多个

-q, --qos

QoS 0/1/2(默认 0);多主题时按出现顺序一一对应

-m, --message

消息体(默认 Hello From MQTTX CLI

-m / -s / -M / --file-read

消息体的四种来源,见下表

-r, --retain

保留消息

-i, --client-id

客户端 ID

-u / -P

用户名 / 密码

-V, --mqtt-version

5.0(默认)/ 3.1.1 / 3.1

-l, --protocol

mqtt(默认)/ mqtts / ws / wss

-f, --format

载荷格式:base64 json hex binary cbor msgpack

-rp, --reconnect-period

重连间隔毫秒,设 0 关闭自动重连

-se, --session-expiry-interval

会话过期间隔(秒)

-up, --user-properties

MQTT 5.0 用户属性,如 -up "name: mqttx cli"

--debug

打开 MQTT.js 调试输出,看协议层细节

消息体的四种来源

写法

含义

-m "文本"

直接给字符串

-s

从标准输入读一条(配 echo / cat / 管道)

-s -M

从标准输入按行读,每行一条消息

-lm

交互模式,逐行输入逐行发送(等价 -s -M

--file-read <路径>

从文件读

-S 1KB

自动生成指定大小的随机载荷(压测用)

遗嘱消息(设备离线上报)

参数

含义

-Wt, --will-topic

遗嘱主题

-Wm, --will-message

遗嘱内容

-Wq, --will-qos

遗嘱 QoS

-Wr, --will-retain

遗嘱是否用保留消息

-Wd, --will-delay-interval

延迟多少秒才发遗嘱

压测与模拟

命令

作用

mqttx bench conn -c 1000

模拟 1000 个并发连接(测 Broker 连接容量)

mqttx bench sub -c 500 -t bench/%i

500 个客户端订阅(测下行吞吐)

mqttx bench pub -c 100 -t t -L 5000

100 个客户端,共发 5000 条(测上行吞吐)

mqttx ls -sc

列出内置模拟场景

mqttx simulate -sc tesla -c 10

用内置场景模拟 10 台设备上报

几个参数要留意:

参数

含义

默认

-c, --count

连接数

1000

-i, --interval

建连间隔(毫秒)

10

-im, --message-interval

发消息间隔(毫秒)

1000

-L, --limit

总消息数上限,0 表示不限

0

%i / %u / %c

主题和 Client ID 里的变量:序号 / 用户名 / 客户端 ID

⚠️ bench 的默认值是 1000 个连接mqttx bench pub 后面什么都不加就回车,会朝对端压一千条连接——千万别对着生产 Broker 裸跑,先显式写 -c 小数值试水。

五个真实场景

场景 1:三十秒判断"设备到底发了没有"

这是最常用的。开两个终端窗口:

# 窗口 A:订阅整个前缀下的所有消息
mqttx sub -t 'factory/#' -h 192.168.1.200 -p 1883 -q 1

# 窗口 B:(设备已经在发的前提下)看看有没有东西过来

如果 A 里什么都没有,问题在设备端或链路上游;如果有消息但内容不对,问题在载荷格式;如果只有部分主题,问题在主题命名。一步就把范围缩小了。

场景 2:用管道把采集结果直接发上去

-s 让消息体从标准输入进来,于是任何能往标准输出打印的命令,都能变成一条 MQTT 消息:

# 手工发一条 JSON
echo '{"deviceId":1,"temp":25.6,"hum":60}' \
  | mqttx pub -t 'factory/line1/plc01/data' -h 192.168.1.200 -q 1 -s

在采集程序(不管是 Python、C# 还是 shell 脚本)里,也可以不做 MQTT 库的集成,先把结果打成 JSON 丢到标准输出,由 mqttx 负责发送。快速验证链路的阶段,这比引入一个客户端 SDK 快得多。

实测的发布端输出:

- Connecting...
√ Connected
- Message publishing...
√ Message published

场景 3:订阅端看消息,并做格式化

订阅端不加 -f 是原样打印,加了 -f json美化成缩进结构(前提是载荷确实是 JSON):

mqttx sub -t 'factory/line1/#' -h 192.168.1.200 -q 1 -f json

实测输出:

received_at: 2026-09-20T12:57:12.203Z, topic: factory/line1/plc01/data, qos: 1, size: 27B
{
  "deviceId": 1,
  "temp": 25.6,
  "hum": 60
}

如果收到的是二进制报文(比如设备直接推的原始寄存器数据),换 -f hex 看:

mqttx sub -t 'device/raw/#' -h 192.168.1.200 -f hex

实测输出(发的是 7 字节 01 03 04 41 CC CC CD):

received_at: 2026-09-20T12:57:36.343Z, topic: device/raw/1, qos: 1, size: 7B
0103 0441 cccc cd

Hex 分组显示,41 CC CC CD 这种一眼就能看出是 IEEE754 浮点数 25.6

但这里有个坑-f json强制按 JSON 解析的,收到非 JSON 载荷时会直接刷错误:

× SyntaxError: Unexpected token '', "A??" is not valid JSON

所以别在既收 JSON 又收二进制的主题上用 -f json,老老实实看原始输出、需要时单独订阅。

场景 4:自动记录 + 落盘

订阅端可以边收边写文件,长时间挂机观察设备行为时很有用:

# 追加写入一个文件(适合累积日志)
mqttx sub -t 'factory/#' -h 192.168.1.200 --file-write factory.log

# 每条消息存成一个独立文件(适合分析单条报文)
mqttx sub -t 'factory/#' -h 192.168.1.200 --file-save ./dump

# 换分隔符,方便后续用脚本按行切分
mqttx sub -t 'factory/#' -h 192.168.1.200 --file-write a.log --delimiter ','

场景 5:上线前压一下

联调通了、要上线之前,值得做两件事:

# ① 测 Broker 能扛多少连接
mqttx bench conn -c 500 -i 10

# ② 测上行吞吐:20 个客户端,每个每秒 5 条(间隔 200ms),共 1000 条
mqttx bench pub -c 20 -im 200 -L 1000 -t 'bench/%i' \
  -h 192.168.1.200 -q 1 -m 'ping'

实测输出:

❯  Starting publish benchmark, connections: 2, req interval: 10ms, message interval: 200ms
√  Created 2 connections in 1.441s
Published total: 5, message rate: 5/s
√ All 5 messages have been sent, reaching the limit of 5.

%i 会被替换成客户端序号,于是每个连接往不同主题发,不会互相覆盖。配合 --payload-size 1KB 还能模拟真实载荷大小。

主题命名规范:现在花十分钟,后面省很多事

主题一旦上线就很难改(改了所有订阅方都得跟着改),建议一开始就定好:

原则

从粗到细分层

factory/line1/plc01/temp

plc01_line1_temp

用设备唯一标识,别用位置描述

.../plc01/...

.../第三个柜子/...

数据用途单独一层

.../plc01/status.../plc01/data

状态和数值混在一个主题

全小写、不用空格

factory/line1/temp

Factory/Line 1/Temp

订阅用通配符、发布用具体路径

订阅 factory/line1/#

factory/# 上发

一个补充技巧:共享订阅。 如果你的数据要在多个处理服务之间做负载均衡(同一条消息只需要被其中一个处理),EMQX 支持共享订阅写法:

$share/{组名}/{主题}     例如订阅:$share/workers/factory/line1/#

同一个组内多个订阅者,消息只会投给其中一个。这个能力由 Broker 提供(EMQX 支持,部分开源 Broker 也支持),不是 MQTT 协议本身的语法,用之前确认一下你的 Broker 版本。

容易踩的坑

现象

原因

解法

npm 装出来是旧版本

registry 镜像 / 本地缓存的旧元数据

显式写 mqttx-cli@latest,或改用独立二进制

sub -f json 一直刷 SyntaxError

-f json 强制解析,收到非 JSON 载荷必然报错

去掉 -f,或按实际格式用 -f hex / -f base64

收到的消息时间对不上本机

received_atUTC(结尾带 Z

自己加 8 小时看,或按 UTC 统一处理

两个客户端互相把对方踢下线

Client ID 重复,Broker 会断开旧连接

使用默认的随机 ID,或保证全局唯一

QoS 1 收到重复消息

QoS 1 的语义是"至少一次"

业务侧用消息 ID 做幂等,别指望不重复

保留消息只有一条

Retain 只存每个主题的最后一条

要历史就靠订阅端落盘

订阅了 factory/# 却收不到消息

主题路径层级不对,或 #+ 位置非法

先用 mqttx sub -t '#' 全量订阅确认到底有什么在发

订阅不到 Broker 自身的指标

$SYS/ 开头不被通配符匹配

显式写 mqttx sub -t '$SYS/#'

命令全对但连不上

端口没放行(云服务器安全组 / 防火墙)

确认 1883 或 8883 是否放行;TLS 要连 8883

服务器上跑不起来

以为装了桌面版就有 CLI

两者是两个安装包,CLI 要单独装

-f hex 发出去的数据对不上

Hex 字符串被当成普通文本发了

确认加了 -f hex,且字符串是空格分隔的十六进制

上手路径

第一阶段:先能用(半小时)

  1. 装桌面版,连 broker.emqx.io:1883

  2. 订阅 #,看看公共服务器上都有什么消息在飞;

  3. 自己发一条,确认能收到;

  4. 记住三件事:主题怎么分层、QoS 在哪选、载荷格式在哪切。

第二阶段:接到自己的环境(一小时内)

  1. 装 CLI(独立二进制最省事);

  2. mqttx conn 确认能连上你的 Broker;

  3. mqttx sub -t '#' 看你的环境里到底有哪些主题在发——这一步经常直接发现问题

  4. mqttx pub -s 配管道发一条,验证上行。

第三阶段:进工具链

  1. mqttx conn 的返回码接进 CI 或监控脚本,做成连通性检查;

  2. 给关键设备配上遗嘱消息,实现离线告警;

  3. 上线前用 bench 跑一轮,心里有个数。

第四阶段:按需深入

  1. 载荷是二进制的,用 -f hex / -f base64 摸清结构;

  2. 配 TLS 和认证;

  3. 需要模拟成百上千台设备时,用 simulate 内置场景。

参考

  • 项目主页:https://mqttx.app

  • 桌面版与 CLI 下载:https://mqttx.app/downloads

  • CLI 文档:https://mqttx.app/docs/cli

  • 桌面版手册:https://mqttx.app/docs

  • 源码仓库:https://github.com/emqx/MQTTX

  • 公共测试 Broker:broker.emqx.io(TCP 1883 / SSL 8883)