Mosquitto Persistence: Define What Survives a Broker Restart After an Acknowledgement

In Mosquitto 2.0.20, enabling persistence does not make every MQTT acknowledgement a synchronous database checkpoint. The broker can acknowledge a retained QoS 1 publication while its newest state is still only in memory. Define restart expectations from persistence configuration and observed checkpoint behavior, then test orderly exit and abrupt process termination separately.

This guide pins Eclipse Mosquitto 2.0.20, its configuration manual and persistence implementation. Three real loopback broker experiments were executed with synthetic retained values. They are process-restart tests, not power-loss, storage-endurance or downstream database tests.

Inventory the effective persistence configuration

Setting Meaning in the pinned release Evidence to retain
persistence Enables on-disk connection, subscription and message state; default false Effective loaded configuration
persistence_location Directory for the database; otherwise current directory Resolved path, service ownership and mount
persistence_file Database filename; default mosquitto.db Actual file and restart selection
autosave_interval Time interval, or change threshold under the corresponding mode Value and autosave_on_changes together
autosave_on_changes Selects change counting rather than elapsed seconds Whether time-based reasoning is applicable

Do not inspect one configuration fragment and assume it is the file used by the service. Record the process arguments, included configuration and broker version. Check that the service can create the database in the intended directory and that it restarts from the same location.

All three isolated Mosquitto2.0.20 cases received a QoS1 PUBACK with autosave interval zero. Orderly exit wrote the database and the retained value returned after restart. SIGKILL before a checkpoint produced no database and no retained value during the test readback. SIGUSR1 checkpoint followed by SIGKILL restored the retained value.
Executed loopback observations with periodic saves disabled. Process termination does not simulate host power loss or storage-controller failure.

Interpret autosave settings together

The 2.0.20 manual gives a default autosave interval of 1,800 seconds. With time-based autosave and an interval of zero, saving occurs at broker exit or in response to SIGUSR1 rather than periodically.

With autosave_on_changes true, the broker counts relevant subscription changes, retained messages and queued messages; the interval becomes a change threshold. Treating that number as seconds produces a false loss-window estimate.

Even a configured periodic interval is not an application promise that every acknowledged message survives a host failure within a precise duration. Scheduling, failed writes and storage behavior still matter. Establish a product requirement and measure the relevant boundary instead of turning an option name into a durability guarantee.

What the source establishes

The persistence path serializes selected in-memory state into a temporary database file, attempts to flush and synchronize it on the non-Windows path, closes it and renames it into place. This is a checkpoint operation distinct from the per-publication acknowledgement observed by a client.

That source ordering helps explain the restart experiments, but it is not proof of every underlying filesystem or device’s power-loss behavior. File creation, a “saving” log line, signal delivery and durable hardware completion are different observations.

Keep checkpoint errors visible. A configured persistence path that is unwritable, full or backed by an unexpected volatile mount can invalidate the intended recovery contract even while ordinary MQTT traffic continues.

Executed three-case campaign

The broker and command-line clients were built from the official 2.0.20 tag using GCC 14.2. TLS, WebSockets, dynamic plugins and documentation builds were disabled. Each case used a fresh directory, a loopback-only listener, persistence enabled, autosave_interval zero and autosave_on_changes false. No production broker, credential or external endpoint was involved.

For each case, the client published one synthetic retained value at QoS 1 and its debug output confirmed PUBACK. The harness then applied the specified process action, restarted the broker with the same configuration and subscribed to the test topic.

Process action after PUBACK Database after stop Restart observation
Orderly termination Present Expected retained value received
SIGKILL before any checkpoint Absent No retained value during one-second subscriber wait
SIGUSR1, wait for database creation, then SIGKILL Present Expected retained value received

All three cases received PUBACK before their stop action. The difference was whether the new state reached a checkpoint before abrupt termination. The checkpoint case waited for the resulting database file, rather than assuming that sending SIGUSR1 meant saving had completed.

Do not overgeneralize the retained-message result

The campaign tested one retained topic in fresh broker instances. It did not establish recovery of persistent-client subscriptions, queued offline messages, every QoS handshake phase, expired messages or large databases.

Add those cases according to the actual product requirement. Session settings and message expiry can legitimately remove state independently of checkpoint timing. Receiving a retained value after restart also does not prove that a downstream consumer committed it.

SIGKILL removes the broker process while the operating system and storage remain running. A power-loss campaign must use the real filesystem, storage hardware and safe test equipment, with an independent record of published and recovered identities. Do not relabel the process test as a power-cut result.

Build a release acceptance matrix

  1. Record exact broker build, persistence settings, database path and service ownership.
  2. Confirm retained-state recovery after an orderly restart.
  3. Repeat abrupt process termination before and after an observed checkpoint.
  4. Exercise the persistent Session and queued-message states the product actually depends on.
  5. Inject controlled storage failures and verify error visibility without claiming protected acceptance.
  6. Qualify power loss separately if the product promises survival of that event.

Keep compatible database backups when changing broker versions; the manual notes that persistence format can change and that newer writes use the current format. Test rollback rather than assuming an older binary can read a newly written database.

The useful deliverable is a precise recovery claim: which state, under which settings, survives which tested interruption. The executed evidence shows why a PUBACK and a persistence checkpoint must remain separate entries in that claim.

Similar Posts