mercurioctl

Administers a running broker from the command line: clients and sessions, bans, retained messages, subscriptions, listeners, bridges and plugins, the log level, reloads and dynamic security.

It sends the commands of the admin API over MQTT 5, and prints the answers as tables, or as JSON for scripts.

Installing

Each release has .deb and .rpm packages and a .tar.gz for x86_64, aarch64 and armv7 Linux. The mercuriod packages recommend it; from downloaded files, install both at once:

# Debian, Ubuntu, Raspberry Pi OS
sudo apt install ./mercuriod_*.deb ./mercurioctl_*.deb

# Fedora, RHEL, openSUSE
sudo dnf install ./mercuriod-*.rpm ./mercurioctl-*.rpm

Or with cargo: cargo install mercurioctl.

Connecting

Without connection options, mercurioctl connects through the broker's admin socket, /run/mercurio/admin.sock, when that file exists. There, as root or a member of the mercurio group, every command works without credentials. Without the socket, it connects to localhost:1883.

# On the broker's host
mercurioctl client list

# Another broker, over TLS; asks for the password
mercurioctl -H broker.example.com -p 8883 --tls -u ops client list

# Logging in with SCRAM-SHA-256, so the password never reaches the broker
mercurioctl -H broker.example.com --auth-method scram-sha-256 -u ops client list

# An admin socket somewhere else
mercurioctl --unix /run/user/1000/mercurio/admin.sock broker info

Connection options go before the command. Each can also be set with an environment variable, which the option overrides:

OptionVariableMeaningDefault
-H, --host, -p, --portMERCURIOCTL_HOST, MERCURIOCTL_PORTBroker over TCPadmin socket, else localhost:1883
--unix PATHMERCURIOCTL_UNIXBroker over a Unix socket
-u, --username, -P, --passwordMERCURIOCTL_USERNAME, MERCURIOCTL_PASSWORDCredentials
--tls, --cafile, --insecureMERCURIOCTL_TLS, MERCURIOCTL_CAFILE, MERCURIOCTL_INSECURETLS, verified with the operating system's certificate store or only the --cafile CA, or not at all; --cafile and --insecure imply --tls
--cert PATH, --key PATHMERCURIOCTL_CERT, MERCURIOCTL_KEYClient certificate and its private key, both PEM; each needs the other, and they imply --tls
--ws, --ws-path PATHMERCURIOCTL_WS, MERCURIOCTL_WS_PATHMQTT over a WebSocket on the host and port, wss:// with TLS, at this path/mqtt
-i, --client-idMERCURIOCTL_CLIENT_IDClient idassigned by the broker
--timeout SECONDSMERCURIOCTL_TIMEOUTLongest wait for the answer, connecting included10
--jsonPrint the answer's data as JSONtables

MERCURIOCTL_TLS, MERCURIOCTL_INSECURE and MERCURIOCTL_WS take 1/0, yes/no, on/off or true/false. An empty variable counts as unset.

Commands

Commands are mercurioctl <group> <verb>. What each one does and returns is in the command reference; --help after any of them lists its options.

CommandRuns
client list [--connected | --offline] [--prefix P] [--user U] [--address A] [--mount-point M]listClients
client show <clientid> [--mount-point M]getClient
client disconnect <clientid> [--mount-point M] [--no-will] [--reason-code C]disconnectClient; C in decimal or 0x..
client delete-session <clientid> [--mount-point M] [--disconnect] [--yes]deleteSession; asks for confirmation first, or needs --yes off a terminal
ban add <clientid|username|address> <value> [--prefix] [--duration S] [--reason R]addBan
ban remove <type> <value> [--prefix]removeBan
ban listlistBans
retained list [filter]listRetained, # by default
retained show <topic>getRetained
retained delete <filter> [--yes]deleteRetained; a filter with + or # asks for confirmation first, or needs --yes off a terminal
subscription list [--prefix P]listSubscriptions
subscription subscribers <filter>getSubscribers
broker infogetBrokerInfo
broker configgetConfig
broker log-level [level]getLogLevel, or setLogLevel with a level
broker reloadreload
listener list, bridge list, plugin listlistListeners, listBridges, listPlugins

Each mount point has its own client ids. When an id is on more than one, client show, disconnect and delete-session need --mount-point, "" for a listener without one; the broker's error lists the mount points to choose from.

The client, ban, retained and subscription lists also take --offset N and --count N.

# Clients connected from one network
mercurioctl client list --connected --address 10.1.0.0/16

# Disconnect a client without publishing its will, then ban its address for an hour
mercurioctl client disconnect sensor-7 --no-will
mercurioctl ban add address 203.0.113.0/24 --duration 3600 --reason flooding

# Retained messages under a retired prefix, then delete them
mercurioctl retained list 'old/#'
mercurioctl retained delete 'old/#'

# Debug one module until the next restart
mercurioctl broker log-level info,mercurio_server::session=debug

Dynamic security

mercurioctl dynsec runs the dynamic security commands under mosquitto_ctrl's names in kebab-case: createClient is dynsec create-client, addRoleACL is dynsec add-role-acl.

# A role that may publish under sensors/, a group with it, and a client in the group
mercurioctl dynsec create-role sensor
mercurioctl dynsec add-role-acl sensor publishClientSend 'sensors/#' allow
mercurioctl dynsec create-group sensors --role sensor
mercurioctl dynsec create-client s1 --group sensors

mercurioctl dynsec get-client s1

Output

Lists print as tables, other answers as name: value lines. Times are in UTC, and empty values print as -:

$ mercurioctl client list
CLIENT ID  MOUNT POINT  USERNAME  CONNECTED  ADDRESS          SINCE                 SUBS  QUEUED  INFLIGHT  DROPPED
monitor    -            -         true       127.0.0.1:41302  2026-11-10 20:39:05Z  1     0       0         0

Shell completions

mercurioctl completions <shell> prints a completion script for bash, zsh, fish, elvish or powershell:

mercurioctl completions bash > ~/.local/share/bash-completion/completions/mercurioctl
mercurioctl completions zsh > "${fpath[1]}/_mercurioctl"

Exit status

StatusMeans
0Success
1The broker refused: the command failed, with its code in parentheses after the message, or access control refused the request or its answer topic. broker reload also exits 1 when any file failed to load, after printing the table.
2The broker couldn't be reached, refused the login, closed the connection, or didn't answer within --timeout
3Wrong usage, such as an unknown option, mismatched passwords, or a destructive command not confirmed

Messages go to standard error, so scripts can read the output:

# Disconnect every client of a retired user
mercurioctl --json client list --user legacy --connected |
    jq -r '.clients[] | [.clientid, .mountpoint // ""] | @tsv' |
    while IFS=$'\t' read -r id mount; do
        mercurioctl client disconnect "$id" --mount-point "$mount"
    done