Message Persistency
mqBase uses a custom Mosquitto plugin to persist MQTT messages to a libSQL database. This page explains the key concepts behind the persistence mechanism.
Overview
When a message is published to mqBase:
The plugin generates a unique ULID (Universally Unique Lexicographically Sortable Identifier)
The ULID is attached to the message as an MQTT v5 user property
The message is queued for batch insertion into the libSQL database
Subscribers receive the message with the ULID header included
This design enables powerful features like:
Message tracing — Track messages across systems using the ULID
Database correlation — Query the exact message in the database using the ULID from the MQTT header
Synchronized deletion — Delete messages from both the broker (retained) and database atomically
ULID as Primary Key
What is ULID?
ULID (Universally Unique Lexicographically Sortable Identifier) is a 26-character identifier that combines:
Timestamp (first 10 characters) — Millisecond precision, sortable
Randomness (last 16 characters) — Cryptographically random
Example ULID: 01ARZ3NDEKTSV4RRFFQ69G5FAV
Why ULID Instead of UUID or Auto-Increment?
Sortable by time
✅ Yes
❌ No
✅ Yes
Globally unique
✅ Yes
✅ Yes
❌ No
No coordination needed
✅ Yes
✅ Yes
❌ No
Compact (26 chars)
✅ Yes
❌ No (36 chars)
✅ Yes
Embeddable in messages
✅ Yes
✅ Yes
❌ No
Works in distributed systems
✅ Yes
✅ Yes
❌ No
ULID in MQTT Messages
The plugin adds the ULID as an MQTT v5 user property to every published message:
This means:
Publishers don't need to generate IDs — the broker handles it
Subscribers receive the ULID with the message
Applications can use the ULID to query the database for the exact message
Extracting ULID from Messages
JavaScript (MQTT.js)
Python (paho-mqtt)
Querying by ULID
Since ULIDs are time-sortable and the database is indexed on ULID, you can efficiently:
Synchronized Retained Message Deletion
The Problem
In standard MQTT, you delete a retained message by publishing an empty payload with the retain flag set:
This clears the retained message from the broker, but the message remains in the database. This creates inconsistency between the broker state and the persisted data.
The Solution
mqBase's plugin detects retained message deletions and automatically removes the corresponding record from the database.
How It Works
When you publish an empty retained message, the plugin intercepts it
The plugin looks for a
uliduser property in the delete messageIf a ULID is provided, that specific record is deleted from the database
If no ULID is provided, the most recent message for that topic is deleted
mosquitto_pub Example
Simply publish an empty retained message — the plugin deletes the most recent database entry for that topic:
JavaScript Example
Python Example
Use Cases
Clear the latest sensor reading
Delete by topic (slow SQL query since without ULID the latest stored event has to be found first before deletion)
Undo the latest publish by ULID
Delete by ULID (faster SQL query execution)
Clean up old retained messages
Query database, delete by ULIDs
Bulk cleanup
Use data retention (plugin_opt_retention_days)
Database Schema
Messages are stored in the msg table:
Indexes
The plugin automatically creates indexes for optimal query performance:
idx_msg_topic— Fast topic-based lookupsidx_msg_topic_ulid— Efficient queries combining topic and time
Best Practices
For Message Tracing
Subscribe to messages with QoS 1 or 2 to ensure delivery
Extract the ULID from the user properties
Log the ULID for later correlation with database records
For Data Cleanup
Set
plugin_opt_retention_daysfor automatic cleanup of old messagesUse ULID-based deletion for targeted cleanup of specific messages
Query the Admin UI's Database tab to find messages before deleting
For High-Throughput Systems
Tune
plugin_opt_batch_sizeandplugin_opt_flush_intervalfor your workloadULIDs are generated with sub-millisecond uniqueness — no bottleneck at high rates
Database operations are batched and non-blocking for publishers
The ULID is added to all published messages, including those on excluded topics. This ensures consistent message identification even when persistence is disabled for specific topics.
Last updated

