MQTT Payload Schema Versioning for SCADA Edge
Versioning MQTT telemetry payloads so historians, HMI clients, MES connectors and analytics survive a field change instead of breaking on one.
Payload changes are interface changes
MQTT makes publishing easy, but that can hide the fact that every payload is an interface contract. A gateway firmware update, new sensor, renamed field, changed timestamp meaning, or different quality code can break a historian connector just as surely as a changed PLC address can break an HMI tag.
The topic name is only part of the interface. Consumers also depend on:
- Field names and nesting.
- Data types and engineering units.
- Timestamp source and format.
- Quality and stale-data meaning.
- Null, missing, and default value behavior.
- Whether messages are full snapshots, deltas, or events.
- Retain, QoS, and replay behavior.
Schema versioning is not paperwork for software teams. It is how operations avoids silent bad data when edge devices change.
Put the version where consumers can see it
A version hidden in a PDF or project folder is not enough. Include a schema version in the payload or in a predictable metadata topic.
A simple telemetry payload might include:
{
"schemaVersion": "2.1",
"source": "line-3/oven-2/gateway-a",
"timestamp": "2026-06-25T08:14:22.341Z",
"quality": "good",
"metrics": {
"zone1TemperatureC": 184.6,
"conveyorSpeedMpm": 12.4
}
}
For Sparkplug B, use the payload model and birth certificate behavior consistently. The same principle still applies: consumers need to know which metric names, aliases, units, and data types are valid for that device at that time.
Separate additive and breaking changes
Not every change should force every consumer to stop. Define what your project treats as additive versus breaking.
| Change | Usually safe? | Field concern |
|---|---|---|
| Add a new optional metric | Often safe | Old consumers should ignore unknown fields |
| Add a required field | Breaking | Old publishers cannot provide it |
| Rename a metric | Breaking | Historian mappings and dashboards may go stale |
| Change unit from bar to kPa | Breaking | Values look plausible but wrong |
| Change timestamp from gateway time to PLC time | Breaking | Event ordering and reports change |
| Add a new quality code | Possibly breaking | Consumers may treat it as good or unknown |
| Change snapshot to delta publish | Breaking | Missing fields may be misread as zero or null |
Field systems should be conservative. A value that is wrong but plausible is more dangerous than a value that clearly fails validation.
Keep timestamp and quality semantics stable
Most MQTT telemetry problems show up later in historian reports, not at the moment of publishing. Timestamp and quality fields deserve special care.
Document these rules for each schema version:
- Is
timestampgenerated by the PLC, edge gateway, broker ingestion layer, or consuming application? - Is it UTC, local time with offset, or local time without offset?
- Does the timestamp represent sample time, publish time, or broker receive time?
- What quality values exist:
good,bad,uncertain,stale,substituted,manual? - Does a stale metric stay in the last snapshot, disappear, or appear with bad quality?
Do not change any of these quietly. A historian backfill process and a live HMI display may both subscribe to the same topic but use the timestamp differently.
Use compatibility windows during rollout
Industrial rollouts are rarely atomic. One line may be updated today, another next month, and a third may stay on old firmware until the next shutdown. Design for a compatibility window.
Practical approaches include:
- Publish both old and new fields for a defined time, then remove the old field after consumers migrate.
- Create a new topic branch for a breaking schema, such as
v2, while leavingv1active temporarily. - Update historian mappings in a test namespace before moving production subscriptions.
- Let the gateway publish its schema version and firmware version on birth or startup.
- Keep a small subscriber test tool that validates payload shape before production cutover.
Avoid indefinite dual publishing unless there is a real support reason. Two schemas that never retire become two systems to maintain.
Validate with real consumers
A JSON schema check is useful, but it is not enough. Commissioning should prove that each important consumer handles the new payload correctly.
Check at least these paths:
- HMI or SCADA client displays live values with correct units and quality.
- Historian stores values under the expected tag names and timestamps.
- MES connector accepts events without creating duplicate or missing transactions.
- Alarm or notification logic handles missing and bad-quality values safely.
- Analytics or dashboard jobs ignore unknown optional fields.
- Store-and-forward replay does not make old payloads look like current data.
Use one normal message, one bad-quality message, one missing optional field, one retained or replayed message, and one version mismatch case. This catches more issues than watching only a happy-path publish.
Common failure modes
Unit changes without a field name change
A pressure value moves from bar to kPa but keeps the same field name. The trend still draws a line, so the failure looks like a process change. Include units in metadata, tag mapping, or field names where appropriate, and treat unit changes as breaking.
Consumers assume missing means zero
Delta payloads or filtered publishes may omit unchanged metrics. If a consumer converts missing to zero, reports and alarms become wrong. Define whether missing means unchanged, unavailable, not configured, or invalid.
Retained messages hide old schema
A retained message from an old gateway can be delivered to a new subscriber after deployment. The subscriber should check schema version and timestamp before trusting it.
Quality vocabulary drifts
One gateway publishes bad, another publishes BAD, and a third publishes 0. Normalize quality values or provide a clear mapping table. Do not let every consumer guess.
Test tools are more tolerant than production connectors
A command-line subscriber may happily print any JSON. The historian connector may require exact field names and types. Test with the real connector whenever possible.
A small versioning record is enough
The record does not need to be heavy. For each schema version, keep:
- Version number and release date.
- Example payloads for normal, bad-quality, and replayed messages.
- Field list with type, unit, required/optional status, and meaning.
- Timestamp and quality rules.
- Known consumers and migration status.
- Breaking changes from the previous version.
- Rollback behavior if the edge update is reverted.
Good schema versioning makes MQTT boring in production. Operators see current values, historians store the right data, and engineers can change edge telemetry without turning every deployment into a forensic exercise.