Mercurio reads mosquitto's password and ACL files as they are and publishes the same $SYS topics. This page maps each mosquitto option to its Mercurio equivalent.
Step by step
Point password_file and acl_file at your existing files. Hashes written by mosquitto_passwd, $7$ and $6$, are recognised.
Translate mosquitto.conf into TOML with the table below.
Start mercuriod on another port, point a few clients at it, then move the rest.
Retained messages and persistent sessions are not imported from mosquitto's database; clients with persistent sessions start new ones, and retained messages need to be published again.
In mosquitto 2, per_listener_settings decides whether authentication is global or per listener. In Mercurio, [auth] applies everywhere, and a listener with its own [listeners.auth] uses that instead.
Option mapping
Listeners
mosquitto
Mercurio
listener PORT [ADDRESS]
[server] port/host, or a [[listeners]] entry
listener 0 /path/to/socket
[[listeners]] path
protocol websockets
protocol = "websocket", or [server] websocket_port
http_dir
http_dir
bind_interface
bind_interface
socket_domain
the address in host, such as "::"
mount_point
mount_point
max_connections
[server] max_connections, and per listener
enable_proxy_protocol
proxy_protocol = true, with proxy_from naming the proxies
TLS
mosquitto
Mercurio, in [server.tls] or [listeners.tls]
certfile, keyfile
cert_path, key_path, with enabled = true
cafile with require_certificate true
ca_path
cafile with require_certificate false
ca_path with require_certificate = false
crlfile
crl_path, with crl_end_entity_only = true to check only the client's own certificate as mosquitto does; by default its intermediate CAs need CRLs too
use_identity_as_username
identity_as_username
use_subject_as_username
subject_as_username
tls_version tlsv1.3
min_version = "1.3"
psk_hint, psk_file
not supported
Security
mosquitto
Mercurio
allow_anonymous
[auth] enabled = true with allow_anonymous
password_file, acl_file
the same, in [auth]
dynamic security plugin
[auth] dynamic_security, with the same commands and the same order of roles, groups and priorities; convert mosquitto's dynamic-security.json, passwords included, with mercuriod dynsec-import, or start a new file with mercuriod dynsec-init
mosquitto_ctrl dynsec …
mercurioctl dynsec …, with the same commands in kebab-case; mosquitto_ctrl dynsec init is mercuriod dynsec-init
mosquitto-go-auth HTTP backend
[auth.http]
none: mosquitto has no built-in enhanced authentication method
SCRAM-SHA-256, offered with password_file and dynamic_security. Passwords from mosquitto_passwd or dynsec-import have no SCRAM keys: they keep working for plain logins and get keys when set again
max_inflight, for messages to clients, lowered further by the client's own Receive Maximum; receive_maximum for QoS 2 from clients
upgrade_outgoing_qos
upgrade_outgoing_qos
use_username_as_clientid
use_username_as_clientid, in [[listeners]]; the main listener has none, so serve such clients on an extra listener
persistent_client_expiration 1w
persistent_client_expiration = 604800, in seconds
sys_interval
sys_interval
persistence, persistence_location
[storage] backend = "sqlite", path; written as changes happen
include_dir
include_dir, with *.toml files
Logging
mosquitto
Mercurio, in [logging]
log_dest stdout
the default
log_dest file PATH
file = "PATH"
log_dest syslog
syslog = true
log_type
level, per module if needed
connection_messages
connection_messages
Bridges
mosquitto
Mercurio, in [[bridges]]
connection NAME
name
address host:port [host:port …]
host/port, or addresses
topic PATTERN DIRECTION QOS LOCAL REMOTE
a [[bridges.topics]] entry: pattern, direction, qos, local_prefix, remote_prefix
bridge_protocol_version mqttv311
protocol_version = "mqttv311"
remote_clientid, remote_username, remote_password
client_id, username, password
bridge_cafile, bridge_certfile, bridge_keyfile
[bridges.tls]ca_path, cert_path, key_path
notifications
notifications
notification_topic
notification_topic
notifications_local_only
notifications_local_only; true by default, where mosquitto's default is false, as Mercurio and other brokers refuse client publishes to the default $SYS topic
keepalive_interval
keepalive
cleansession
clean_start
restart_timeout
none: the wait between attempts doubles from a second up to a minute, with jitter
MQTT 5 bridges also take session_expiry, the seconds the remote broker keeps the session, a day by default. Not supported yet: bridge_attempt_unsubscribe, bridge_bind_address, bridge_capath, bridge_insecure, bridge_alpn, bridge_identity and bridge_psk, bridge_max_packet_size, bridge_outgoing_retain, bridge_reload_type, bridge_require_ocsp, bridge_tls_version, idle_timeout, local_cleansession, local_clientid, local_username and local_password (the local side connects in process), round_robin (addresses are always tried in turn), start_type (bridges always start with the broker), threshold and try_private.
Differences to know
Sessions end a week after their client left, by max_session_expiry's default, also those of MQTT 3.x clients without clean session, which mosquitto keeps forever unless persistent_client_expiration is set. Set max_session_expiry = "unlimited" to keep them as mosquitto does.
max_keepalive doesn't apply to MQTT 3.1.1 and 3.1 clients, as those protocols can't tell a client the server's limit. Mosquitto refuses them when they ask for a longer keep-alive, or for none; Mercurio accepts them with the keep-alive they asked for.
Mosquitto lets any client take over any client id. Mercurio refuses a client of another user with Not Authorized while the id has a session, and leaves that session alone. If a stale session blocks the new owner of an id, delete it with mercurioctl client delete-session <clientid> or wait for it to expire; see Client id ownership.
Mosquitto shares one set of client ids across all listeners. In Mercurio each mount_point has its own: clients with the same id on listeners with different mount points get two sessions, where mosquitto would have one take the other over.
A bridge's local side is trusted: this broker's ACLs don't restrict what it forwards in.
Bridges to MQTT 3.1.1 brokers drop the remote broker's echo of what they forwarded, without mosquitto's try_private extension; see Bridges.
Over HTTP authentication, clientid is empty in login requests.
When dynamic security's anonymous group changes, anonymous clients of Unix socket listeners stay connected; mosquitto disconnects every anonymous client. Their access still follows the new group at once.
The answer to a $CONTROL request goes only to the client that sent it. Other clients subscribed to …/response don't see it.
An MQTT 5 client that disconnects with an error reason code, 0x80 or above, gets its will published, as the specification says; only a normal disconnection (0x00) discards it. Mosquitto discards the will on any DISCONNECT except 0x04.