XMQ
Credits:The XMQ web site is provided by Linotex.The XMQ and SPTK Windows installers are created with Advanced Installer free Open-Source license.
There were 0 unique visitors to this page

XMQ MQTT Server Documentation

XMQ User Manual

XMQ is an MQTT 5, 3.1.1, and 3.1 server. This manual covers installing it, tuning the host it runs on, configuring it from the configuration interface, and proving that the result works.

Supported operating systems

XMQ is built and packaged for the systems below. Each is a 64-bit x86 build, packaged in the format native to that system.

SystemVersionsPackage
Debiantrixie, forky.deb
Ubuntu25.04, 25.10, 26.04.deb
Fedora42, 43, 44.rpm
Oracle Linux10.rpm
FreeBSD15pkg
Windows10, 11, Serverinstaller

Other Linux distributions of comparable vintage generally work when built from source, but only the versions listed here are tested and packaged.

Download and install binaries

The only official download location is here. Select the latest SPTK version and your operating system, and download xmq_server package.

Packages are named XMQ-server and install under /usr/localon Linux and FreeBSD. The server, the utilities, the configuration interface, and the load-test scenarios all come from that one package.

The dependencies for Linux include brotli and pcre2 packages that are included in all major Linux distributions. On FreeBSD pkg resolves them from the official repository. The dependencies for Windows are installed with XMQ.

The package file name carries the version and the architecture, so the commands below use a wildcard. Run them in the directory the package was downloaded to.

Debian and Ubuntu
sudo apt install ./xmq-server_*.deb
Fedora and Oracle Linux
sudo dnf install ./XMQ-server-*.rpm
FreeBSD
sudo pkg install ./XMQ-server-*.pkg

Installing through the package manager rather than dpkg -i orrpm -i lets it resolve the shared libraries the package depends on.

What gets installed
PathContents
/usr/local/binxmq_server and the xmq_pub, xmq_sub,xmq_con, xmq_scn utilities
/etc/xmq/xmq_server.confServer configuration. An existing file is never overwritten by an upgrade
/etc/xmq/xmq_server.conf.templateThe shipped defaults, refreshed on every upgrade, for comparison
/etc/xmq/certsTLS certificates and keys installed from the SSL Keys page
/var/log/xmqServer log
/usr/local/share/xmqLoad-test scenarios, host tuning files, helper scripts

On Windows the equivalents live under C:\ProgramData\xmq, with the program files in C:\Program Files\xmq.

Running the server

The package installs a systemd unit, so on Linux the server is managed the usual way:

sudo systemctl enable --now xmq_server
sudo systemctl status xmq_server
sudo journalctl -u xmq_server -f

On FreeBSD the package installs an rc.d script instead:

sudo sysrc xmq_server_enable=YES
sudo service xmq_server start
sudo service xmq_server status

On Windows, xmq_server --install-service registers it as a Windows service, and --uninstall-service removes it.

Useful options when running it by hand:

OptionMeaning
-c, --configuration-fileUse a configuration file other than the default
-l, --log-fileWrite the log somewhere other than the configured path
--no-cpu-affinityStop pinning threads to physical cores. Affinity is the default and is Linux-only; it understands CPU sets, so it cooperates with containers
-d, --debugVerbose logging, regardless of the configured levels
--set-passwordSet an account's password and exit, reading the password from standard input. The way to give the administrator a password where the configuration interface cannot be reached — see below
--versionPrint the version and exit
Setting the administrator password without the interface

A freshly installed server has an administrator with no password, and until one is set the configuration interface answers on 127.0.0.1 only. On a machine with a console that is exactly right. Where there is no console it is a problem, so the password can also be set from the command line:

printf '%s' 'the-new-password' | sudo -u xmq xmq_server --set-password admin

The password is read from standard input, not taken as an argument, so it does not appear in the process list or the shell history. On a headless server the alternative is to forward the port —ssh -L 18883:127.0.0.1:18883 the-server — and use the interface as usual. In a container neither the console nor the loopback address is available, and the image sets the password from XMQ_ADMIN_PASSWORD for this reason.

Once the server runs, the configuration interface is reachable on port 18883 by default. On a server that has just been installed it answers on that machine only, at https://127.0.0.1:18883, and the admin account it created has no password: sign in as admin leaving the password empty. The Initial Setup page opens straight away, and the password set there is what opens the interface to the rest of the network.

Nothing is shipped with a password. Until the administrator has one, the account cannot be used over MQTT at all and the interface cannot be reached from another machine — so the first sign-in has to be made from the server's own console, or through a forwarded port.

Environment tuning

A default Linux install is tuned for a few thousand sockets, not a few hundred thousand. Below roughly 10,000 concurrent connections the stock settings are fine and this section can be skipped. Above that, the limits below are the ones that bite, and each of them has been hit in real test runs.

Ready-made files are installed with the package under/usr/local/share/xmq/setup, along with a README describing the symptom each one addresses:

FileInstall toPurpose
sysctl.d/mqtt.conf/etc/sysctl.d/File descriptor ceiling, socket buffers, accept queue depth, TCP memory
sysctl.d/port_range.conf/etc/sysctl.d/Widen the ephemeral port range to 10000-65535
limits.d/mqtt.conf/etc/security/limits.d/nofile for login sessions
modules-load.d/nf_conntrack.conf/etc/modules-load.d/Load nf_conntrack before systemd-sysctl runs
nftables.d/xmq-notrack.nft/etc/nftables.d/Exempt the MQTT ports from connection tracking
cd /usr/local/share/xmq/setup
sudo install -m 0644 sysctl.d/mqtt.conf       /etc/sysctl.d/mqtt.conf
sudo install -m 0644 sysctl.d/port_range.conf /etc/sysctl.d/port_range.conf
sudo install -m 0644 limits.d/mqtt.conf       /etc/security/limits.d/mqtt.conf
sudo modprobe nf_conntrack
sudo sysctl --system

Then log out and back in, so the nofile limit applies to your shell.

The three that catch people out
  • One descriptor per connection, plus a handful. The server idles at 17 descriptors, so a limit of exactly 1,000,000 fails at 999,983 connections. The shipped files set 2,000,000, which leaves room.
  • Services do not read limits.d. That file applies to login sessions only. A systemd service gets DefaultLimitNOFILE instead, commonly 524288. The XMQ unit sets LimitNOFILE explicitly for this reason; any unit you write yourself must do the same.
  • A ulimit -n in your shell profile wins. If~/.profile or ~/.bashrc lowers it, an unprivileged process cannot raise it again, and the limit files appear to have no effect.

Both ends need this. Every limit here is per host, and tuning only the server while leaving the client machine at defaults is the most common mistake. Thepreflight.sh script in /usr/local/share/xmq checks a host and exits non-zero if a required setting is missing:

./preflight.sh                          # check this host as a client
./preflight.sh -H broker -r server -p 1883   # check a remote server host

Basic MQTT setup

Everything in this section can be set from the configuration interface, and is written back to/etc/xmq/xmq_server.conf. The user data is stored in the file/etc/xmq/xmq_users.conf. Hand-editing these files is still possible; if you do, restart the server afterwards, since a running server rewrites the files when settings change and would overwrite your edit.

The XMQ configuration interface is available through the browser at https://xmq_host:18883, where xmq_host is the host the XMQ server runs on. It is administered through the admin account. A server that has never been set up is the exception in two ways: it answers at https://127.0.0.1:18883 and nowhere else, and admin has no password yet — sign in with the password field left empty, and set one on the Initial Setup page that opens.

Starting from scratch

The Initial Setup page asks for the few settings a working server cannot be without — an administrator password, a node name, the MQTT, MQTT+SSL, and interface ports, and optionally a Redis address — and builds a configuration around them. It is the quickest way to bring up a new installation, and the way back to a known state when a configuration has been edited into a corner.

The admin account comes first on that page because it is what the interface is administered through: setup creates the account if it is not there, and gives it the password entered either way, so the configuration it produces always comes with a way in. Since a session carries the password it signed in with, changing it ends the current session — sign in again with the new password.

On a server being set up for the first time, that password does one more thing: it is what moves the interface off the loopback address. Until it is set the interface accepts connections from the server's own machine only, because an account that anyone can sign in to without a password has no business being reachable from a network. The account is refused everywhere else in the meantime — an MQTT client offering admin and no password is not connected.

It is the one page that discards settings rather than changing them. Everything it does not ask about is taken from /etc/xmq/xmq_server.conf.template, the copy of the shipped configuration the installer leaves behind, so listeners, bridges, limits, and logging settings all go back to their defaults. The template itself is only read; the result is written to xmq_server.conf.

The accounts are reset with them: xmq_users.conf is rewritten withadmin, using the password entered on the page, and the internalcluster account. MQTT clients that authenticate will need their accounts adding again on the Users page. Installed certificate files are kept, being files of their own rather than configuration.

Submitting restarts the MQTT server, which disconnects every client. Changing the interface port takes effect at once too: the interface starts answering on the new port before it stops answering on the old one, and the browser is sent there. Connections already open are served to the end, so the reply announcing the move still arrives. A port that cannot be taken — because something else holds it — leaves the interface where it was, and the page says so instead of sending the browser nowhere.

A missing configuration is not an error: the server writes a starting one fromxmq_server.conf.template, or from its own defaults if the template is gone too, and comes up on the ports above. A missing xmq_users.conf is written too, with an admin account that has no password and the internal cluster account. No accounts are installed by the package: a password shipped in a file is a password everyone who downloaded the package knows.

When the interface will not start

The Initial Setup page needs the interface to be running, which is no help when the configuration is what stops the server from starting: a port already taken, a listener bound to an address this host does not have, or a file edited into something that will not parse. The same reset is available from the command line, where nothing needs to be running:

sudo systemctl stop xmq
sudo xmq_server --reset-configuration   # or start the service again afterwards

It replaces xmq_server.conf with the starting configuration and carries on into a normal start. The file it replaced is kept beside it asxmq_server.conf.old, since it is usually still worth reading. Accounts are not touched — they are in their own file, and are not what stops a server from starting — except that one for admin is created, without a password, if there are no accounts at all.

Port numbers

Listeners are configured on the Listeners page. Each one is a port, a protocol, and a thread count. The shipped configuration defines two:

PortProtocolPurpose
1883MQTTPlain TCP, the standard MQTT port
8883MQTT+SSLTLS, the standard secure MQTT port
18883HTTPThe configuration interface and its control API

These are the standard MQTT ports, so most clients need no port setting at all. If another broker on the same host already holds them, either stop it or move one of the two: the Listeners page changes XMQ's ports, and the change takes effect as soon as the listener is saved.

A listener also carries a bind address. 0.0.0.0 accepts on every interface; naming one address restricts the listener to it, which is a simple way to keep a port on an internal network. Disabling a listener keeps its settings but closes its port.

The service port itself is set on the Service page, and changing it takes effect at once: the interface starts answering on the new port before it stops answering on the old one, and the page follows it there. Connections already open are served to the end. If something else already holds the port, the interface stays where it is and the page says so.

SSL certificates

An MQTT+SSL listener needs a server key and certificate. Install them from the SSL Keys page: choosing a file uploads its contents, and the server writes it into /etc/xmq/certs(C:\ProgramData\xmq\certs on Windows) and records the path. A previous file of the same name is kept beside the new one with an .old suffix.

  • Server key and server certificate are required for TLS.
  • CA certificate is needed only to verify client certificates.
  • Verify depth of 0 means clients are not asked for a certificate: the TLS listener proves the server's identity and no more. Above 0, a client must present a certificate that the CA certificate validates, within that many intermediate signers.

If the keys are missing or fail to load, the server logs an error, skips the MQTT+SSL listener, and carries on serving the plain one. That is worth checking in the log after installing certificates for the first time.

Logging

The Logging page sets the log file and the level per subject. Theminimum log level is a ceiling rather than a floor: each subject has its own level, and the server clips it to this one. Turning the ceiling down toINFO quietens everything without touching the individual subjects, and turning it up to DEBUG lets them speak at their configured level.

Levels are PANIC, ERROR, WARNING,NOTICE, INFO, DEBUG, from quietest to most verbose. Two subjects deserve care: Publish and Acks produce a line per message, not per client. At the rates XMQ is built for, DEBUGthere can outweigh everything else the server logs and cost real throughput. Leave them at ERROR unless you are chasing something specific.

Log rotation is left to the system. Session errors are always logged atERROR and are not configurable.

Users and anonymous access

Accounts on the Users page serve both MQTT clients and the configuration interface. An administrator may change the configuration; a non-administrator can connect but not administer. Allow anonymous lets MQTT clients connect with no credentials at all; it does not affect the configuration interface, which always requires signing in.

Persistence

Without persistence the server keeps everything in memory and nothing survives a restart. With it, client sessions, their subscriptions, and undelivered QoS 1 and QoS 2 messages are stored in Redis. Redis is a separate service, not part of XMQ: install and start it yourself, then enable persistence on the Persistencepage.

If the server cannot reach Redis at startup it logs the error and keeps running with in-memory storage. The server stays up and nothing is persisted, so the log is worth a look after enabling it.

One setting there is a genuine trade-off. Max queued writes at 0 makes every message wait for its own record to become durable before it is sent: the safest setting, and the slowest. Above 0, record writes pipeline instead, roughly doubling throughput, and the value is approximately how many messages could be lost if the server were killed outright.

Advanced setup

MQTT bridges

A bridge is a client connection XMQ makes to another MQTT broker, carrying an agreed set of topics. The remote broker does not have to be XMQ: bridging to Mosquitto, EMQX, or anything else speaking MQTT works the same way. Bridges are configured on the Bridges page.

A bridge has a direction, and so does each of its topics:

ModeMeaning
outMessages published on this server are forwarded to the remote one
inThis server subscribes to the remote one and republishes what it sends
inoutBoth directions

Each topic entry carries a pattern, a direction of its own, and the QoS to subscribe with. A topic's direction narrows the bridge's: a topic markedout on an inout bridge travels outbound only. Topics keep the name they were published with; there is no rewriting between the two servers. A bridge with no topics carries nothing.

Things worth getting right
  • Client ID must be stable. The remote broker keys the bridge's stored subscriptions and queued messages by it. An id that changes between reconnects leaves orphaned sessions accumulating on the remote. Left empty, XMQ derives one from the two node names, which is stable.
  • Leave clean session off. The remote then keeps the subscriptions and queues messages while the link is down, so a brief outage does not lose them. With it on, the session starts empty each time and anything published while disconnected is gone.
  • Loops. XMQ marks its bridge connections with an origin node, so it will not echo back a message that arrived over the bridge. Bridging through a broker that does not do the same, in both directions, on overlapping topics, can still produce a loop.
  • Encrypted bridges use key files already present on the XMQ host, given by path. That is the opposite of the SSL Keys page, which uploads content. The remote broker must be listening on its TLS port.
Bridging two XMQ servers, step by step

This walks through joining two XMQ servers so that a client on either one sees traffic published on the other. Call them mq-a and mq-b; substitute your own host names throughout. One bridge is enough, defined on mq-a and pointing at mq-b, in inout mode - that single bridge carries both directions. Do not define a second one on mq-b pointing back; see the end of this section for why.

The shipped configuration defines no bridges and no cluster nodes, so the Bridges page is empty on a fresh installation. Everything below is added by hand.

Before you start

  • Both servers installed, running, and reachable from each other on their MQTT port - a bridge is an ordinary outbound MQTT connection, so a firewall between the hosts needs that port open in both directions.
  • Decide which topics to carry. This example uses test/#. Prefer a specific prefix to #: it keeps the link's traffic to what you actually meant to share.
  • An account on each server for the other's bridge to log in as. The bridge authenticates like any client, so it needs a real account on theremote server. A non-administrator account is enough; create it on theUsers page if you do not already have one.

Step 1 - add the bridge on mq-a

Open http://mq-a:18883, sign in as an administrator, and go to theBridges page. It is a master-detail page: the bridge list on top, and the settings of the selected bridge below. Press Add, fill the settings in, and press Save Bridge:

FieldValue on mq-aNotes
Node namemq-bThe name this server knows the remote by. It appears in the log and marks messages that arrived over the link, which is how loops are prevented. A name already used by another bridge is rejected.
Host / portmq-b / 1883The remote MQTT listener, not its configuration port. A second bridge to the same host and port is rejected: it would carry every message twice.
ModeinoutBoth directions.
Usernamethe account on mq-bCredentials for the remote server, not this one.
Passwordits password
Client IDleave emptyXMQ then derives a stable id from the two node names. Set one only if the remote requires a particular id, and never one that varies.
Enabledticked
Clean sessionuntickedSo mq-b keeps the subscriptions and queues messages while the link is down.
EncrypteduntickedTick it only when bridging to the remote's TLS port; it reveals the key file fields, which are paths on this host.

Then fill the Topics table below the settings. Press its Add and give the topic a Pattern of test/#, a Direction ofinout, and a QoS of 1. A bridge with no topics connects and carries nothing, so this table is not optional.

Press Save Bridge. The bridge appears in the list with its topic count, and the configuration file is written immediately.

Step 2 - nothing to do on mq-b

mq-b needs no bridge of its own. It needs only the account the bridge signs in with, which it already has if you used one of its existing users. Nothing on mq-b records that a bridge exists: to it, mq-a's bridge is an ordinary client that subscribes and publishes.

Step 3 - press Apply on each server

This step is easy to miss. Saving a bridge stores it, but does not start the connection. Apply, on the Bridges page, rebuilds the connections from the configuration as it now stands: the bridges that were running are stopped, and the configured ones are started. Press it on mq-a.

Neither server has to be restarted, and mq-b does not have to be up yet: a bridge whose remote is not answering retries on its own, the wait between attempts growing to half a minute and dropping back as soon as it connects.

Restarting the server has the same effect, since bridges are started with it, and remains the way to apply a change made by editing the configuration file directly:

sudo systemctl restart xmq_server

Step 4 - confirm the link came up

With Connections at DEBUG on the Logging page, mq-a's log carries two lines for the bridge:

Bridge to mq-b forwarding 1 outbound topic(s).
Bridge to mq-b (mq-b:1883) connected, 1 inbound topic(s).

Both counts matter. connected with 0 inbound topics means the bridge reached the remote but carries nothing - almost always an empty or mistyped Topics field.

Step 5 - prove a message crosses

Subscribe on one server and publish on the other. The subscriber has no other way to see the message, so receiving it is itself the proof the bridge carried it:

xmq_sub -h mq-b -p 1883 -u user -P secret -t test/bridge -q 1 -v -C 1 -W 15

xmq_pub -h mq-a -p 1883 -u user -P secret -t test/bridge -q 1 -m "over the bridge"

Then swap the two hosts and repeat, to check the other direction: oneinout bridge carries both, but the two use different halves of it, and it is quite possible for one to work while the other does not.

For a measured run rather than a single message, xmq_scn can publish to one server and subscribe on the other:

xmq_scn -s Basic/Point-To-Point-1K-1K-1K-1K.json \
        --host mq-a --port 1883 --subscriber-host mq-b --subscriber-port 1883

Every message it counts has crossed the bridge, so the reported latency includes the extra broker hop and the round trip between the hosts. Compare it against the same scenario run without --subscriber-host to see what the link costs.

If nothing crosses

  • No bridge line in the log at all - Apply was not pressed after the bridge was saved, or the bridge is not enabled. Saving stores the bridge; it does not start it.
  • Repeated connect failures - the host or port is wrong, the port is blocked, or the credentials name an account that does not exist on theremote server. The log names the reason.
  • Connected, nothing carried - the topic pattern does not cover the topic being published. Patterns are matched as MQTT subscriptions:test/# covers test/bridge, while teston its own does not.
  • One direction only - check the mode on both bridges. A bridge inout mode forwards but never subscribes.
  • Everything arrives twice - a bridge is defined on both servers, each covering the same topics. One inout bridge carries both directions by itself, so the second one only moves the same message a second way; remove it. The subscribers on the publishing server still see one copy, which is what makes this look like a delivery fault rather than a configuration one. This is explained under Why one bridge, and not one on each server below.

Why one bridge, and not one on each server

An inout bridge already carries both directions on its own: it subscribes on the remote for what comes in, and subscribes locally for what goes out. A second bridge, defined on the other server and pointing back, adds nothing but a second copy - the message arrives once because this server pulled it, and again because the other server pushed it. Both copies are legitimate deliveries, so nothing detects or suppresses them: a subscriber simply receives everything twice.

Define the bridge on one of the two servers only. Which one does not matter.

Bridged traffic is not sent back the way it came - a message is marked with the node it arrived from, and a bridge subscription is never given a marked message. That marking is XMQ's own, so it only covers the bridges XMQ itself makes. When the broker at the other end is doing the bridging, what protects you is described next.

More than two servers

Bridged traffic is not passed on. A message that reached this server over one bridge is delivered to its own subscribers, but it is not handed to a second bridge - that is the same rule that stops a message going back where it came from, and it cannot tell "back" from "onward".

So the shapes that look natural do not work. In a chainA - B - C, B sees everything from both, but A and C never see each other. In a star, the hub sees every spoke and no spoke sees another.

Give every pair its own bridge instead. Three servers need three:A-B, A-C and B-C, each defined once, on either end. Every server then has a direct link to every other, so nothing needs relaying - and because nothing is relayed, nothing is duplicated either: each message arrives exactly once at each server.

The cost is that the number of bridges grows as the square of the number of servers: three servers need three bridges, four need six, five need ten. Bridging suits a handful of servers, and the arithmetic is what limits it.

Bridging to a broker that is not XMQ

A bridge to Mosquitto, EMQX, or anything else speaking MQTT is configured exactly as above; only the remote's own settings differ. One of them is worth getting right, because it decides whether messages can circulate endlessly between the two brokers.

Configure the remote's bridge to use MQTT 5. In Mosquitto that is one line in its bridge block:

connection xmq
address xmq-host:1883
topic test/# both 0 "" ""
remote_username user
remote_password secret
bridge_protocol_version mqttv50

MQTT 5 defines two subscription options that exist for precisely this purpose.No Local tells the broker not to send a subscriber back what that same connection published, which is what stops a message going round; and Retain As Published keeps a retained message retained as it crosses. A bridge that subscribes with them cannot be echoed to, and XMQ honours both, whoever set them. XMQ's own bridges set them too, which is why a bridge between two XMQ servers needs nothing configured for this.

Mosquitto defaults to mqttv311 instead. Such a bridge still connects and still carries messages, but the loop protection is absent: MQTT 3.1.1 has no subscription options to carry it, and the non-standard "bridge" protocol variant Mosquitto tries first - a protocol level with the high bit set - is not something XMQ accepts. Mosquitto notices the refusal and reconnects as an ordinary client, so the only visible cost is one rejected connection attempt, and the invisible one is that XMQ cannot tell that client is a bridge.

With a 3.1.1 remote bridge, then, keep the topic patterns from overlapping in both directions - carry a/# one way and b/# the other, rather than # both ways - or drive the link entirely from the XMQ side, where the origin marking applies.

Server limits

The Server Limits page holds the thread counts and the per-session bounds. The rule for threads is short: XMQ pins its threads to physical cores, and no thread group should be larger than the host's physical core count. The groups share those cores, so count the send threads, the receive threads, the persistence threads and the per-listener threads together rather than each on its own. Adding threads past that buys contention, not throughput.

MQTT testing suite

xmq_scn runs load-test scenarios described by JSON files. It is broker-neutral: it speaks plain MQTT and can be pointed at Mosquitto, EMQX, NanoMQ or anything else, which is what makes its numbers comparable across brokers.

Scenarios ship in /usr/local/share/xmq. List them with:

xmq_scn --list-scenarios

A scenario file names the client groups, their counts, the topics, and the pacing. The shipped set covers connection ramps, fan-in, fan-out, and point-to-point, at sizes from 10,000 to 1,000,000 connections. Writing a new one is a matter of copying the closest and changing the numbers.

xmq_scn -s Point-To-Point-50K-50K-50K-50K.json --progress
xmq_scn -s 1M-Connections-5K-rate.json -h broker -p 1883
OptionMeaning
-s, --scenarioScenario file. A relative path is looked up in the current directory first, then in the installed scenario directory
-m, --payload-sizeMessage size, overriding the scenario
-r, --publish-rateMessages per second per publisher. 0 means unpaced: as fast as possible
-d, --durationHow long to run
-q, --qosQuality of service to publish with
--max-inflightCap on a publisher's un-acknowledged QoS 1 backlog, so it throttles against its own round-trip time rather than publishing blindly at the configured rate
--id-prefixClient id prefix, so several client hosts don't collide
--progressShow a progress bar

Reaching the larger sizes needs the tuning above on both hosts, and enough source addresses on the client: a connection is identified by its source address and port, so one address runs out of ports long before a million connections. The tested 1,000,000-connection runs used 30 client addresses, about 33,000 connections each. The make_ip_addresses.sh helper in the same directory adds them, andremove_ip_addresses.sh takes them away again:

./make_ip_addresses.sh -s <first three octets> -p <prefix> -f <first host octet> -c 29

Scenarios spread their clients across whatever addresses the host has, so the--id-prefix option keeps client ids distinct when several client machines drive the same broker.

Run the load generator on a different machine from the broker. Sharing a host means measuring the two competing for the same cores, which flatters neither.

Testing your setup

Three small utilities are enough to prove an installation works. All of them take-h host, -p port, -u username,--password, and --version.

Is the server up?
systemctl status xmq_server
tail -f /var/log/xmq/xmq_server.log

The log names each listener it opened at startup, and says which storage it is using: a Redis address, or memory when persistence is off or Redis could not be reached.

Subscribe and publish

In one terminal, subscribe. In another, publish, and watch it arrive:

xmq_sub -h localhost -p 1883 -u user --password secret -t "test/#" -q 1 -v

xmq_pub -h localhost -p 1883 -u user --password secret -t test/hello -m "it works"

Useful xmq_pub options: -r repeats the message a number of times, -g paces it to a rate, -f takes the payload from a file, -s reads it from standard input, and -l stamps a send timestamp into the payload so latency can be measured at the far end.

Testing TLS
xmq_sub -h localhost -p 8883 -u user --password secret \
        -t "test/#" -q 1 -v --cafile /etc/xmq/certs/ca.crt

If this fails while the plain port works, the certificates are the place to look: the server log says whether it managed to load them at startup.

Many connections at once

xmq_con opens a number of sessions and holds them, which is the quickest way to see whether the host limits are in place:

xmq_con -h localhost -p 1883 -u user --password secret -n 10000 --show-counters

If it stops short of the number asked for, the file descriptor limit is the usual cause, on whichever host ran out first. Check both, then see the tuning section.

Checking a bridge

Subscribe on the remote broker, publish on XMQ, and confirm the message crosses:

xmq_sub -h remote-broker -p 1883 -t "bridged/#" -q 1 -v

xmq_pub -h localhost -p 1883 -u user --password secret -t bridged/test -m "over the bridge"

Nothing arriving usually means the bridge is disabled, its topic pattern does not cover the topic, or its direction excludes it. The server log, withConnections at DEBUG, shows the bridge connecting and how many topics it subscribed to.