Fan-out is the few-to-many case, and the one that isolates delivery cost: a handful of publishers on a handful of topics, with a thousand subscribers on each. One received message becomes a thousand sends, so the inbound side is negligible and what is being measured is almost entirely the broker's delivery path.
5 publishers on 5 topics at 50 messages/second each — 250 messages/second inbound — and 1,000 subscribers each subscribed to all five topics, giving 250,000 messages/second delivered. QoS 1, 16-byte payload, 5 minutes. Only 1,005 connections are involved, so this is a throughput test rather than a connection-scale one. The scenario mirrors the Open MQTT Benchmark Suite's singlenode-fanout-5-1000-5-250K case; see the Test Environment page for hardware, tuning and method.
Server
Version
Messages
Achieved rate
Avg latency
CPU
Peak RAM
XMQ
0.9.13
74,998,184
249,993/s
2.5ms
329% mean / 595% peak
22.2 Mb
EMQX
5.8.9
74,989,957
249,966/s
4.0ms
870% mean / 1557% peak
430 Mb
Mosquitto
2.0.22-5build1
31,381,388
104,604/s(below target)
87s
74% mean / 100% peak
2.52 Gb
FlashMQ
1.26.2
74,998,297
249,994/s
2.1ms
384% mean / 477% peak
29 Mb
XMQ
EMQX
Mosquitto
FlashMQ
Latency uses a logarithmic axis: the brokers differ by several orders of magnitude in this scenario, and a linear axis would flatten the faster ones onto the baseline. Hover the chart for per-interval values.
Reading the results
XMQ and EMQX both hold the full 250,000 messages/second, which makes this a clean latency and efficiency comparison rather than a question of capacity. XMQ averages 2.48 ms against EMQX's 4.04 ms, using 2.6× less CPU and 19× less memory — and doing it confined to 8 of the 16 vCPUs, while EMQX had all of them.
XMQ's 22 MB peak is the figure most worth noting. Fan-out holds only 1,005 connections, so almost none of that memory is session state; it reflects how little the delivery path buffers when it keeps up with the send rate.
Mosquitto reached 104,604/s of the 250,000 offered, with latency growing linearly from 8.5 s to 165.9 s — a fixed deficit converting straight into backlog, so the average is bounded by run length rather than settling. Its single event-loop thread is the constraint, and unlike the other limits in this suite that one does not move with better hardware: one thread is one thread on any machine. It did beat its own published 81,000/s for this scenario, which is consistent with faster cores, but the shape is unchanged.
The load generator was never the limit. At 250,000 messages/second the client has to receive and timestamp every message, so it could plausibly have been the bottleneck rather than the broker. It peaked at 442% of the 1600% available — about 28% of the client machine — so both 250K results measure the broker.
If you have any questions or comments regarding this page feel free to drop a line to Alexey Parshin. Design by Michael Perlov.