Fundamentals

Sparkplug B Explained: MQTT for Industrial IoT

Sparkplug B explained: the spBv1.0 topic namespace, NBIRTH/NDEATH and DATA/CMD messages, protobuf payloads, bdSeq and seq, and the primary host application.

Updated · 8 min read

Plain MQTT is deliberately unopinionated: any topic, any payload. That flexibility is a problem in factories, where a SCADA system from one vendor must understand data from PLC gateways built by another. Sparkplug B fills the gap. It is an open specification, maintained by the Eclipse Foundation's Sparkplug Working Group, that defines how to use MQTT for industrial IoT: a fixed topic structure, a binary payload format and rules for knowing whether every device is online. Version 3.0 of the spec is also published as the international standard ISO/IEC 20237.

If you are new to the underlying protocol, start with what is MQTT.

The components of a Sparkplug system

  • MQTT server — any compliant MQTT 3.1.1 or 5 broker.
  • Edge Node — a gateway or device that connects to MQTT, for example a PLC gateway. It publishes its own data and data for the devices behind it.
  • Device — a sensor, PLC or machine attached to an Edge Node. Devices do not connect to MQTT themselves; the Edge Node speaks for them.
  • Host Application — a consumer such as SCADA, MES or a historian that subscribes to data and sends commands. One of them can be designated the Primary Host Application.

The Sparkplug topic namespace

Every Sparkplug B topic follows the same structure:

Topic structure
spBv1.0/<group_id>/<message_type>/<edge_node_id>[/<device_id>]

# Examples
spBv1.0/Plant1/NBIRTH/Gateway-07
spBv1.0/Plant1/DDATA/Gateway-07/Press-3
spBv1.0/Plant1/DCMD/Gateway-07/Press-3
  • spBv1.0 — the namespace and version of the payload definition.
  • group_id — a logical grouping of Edge Nodes, such as a site or production line.
  • message_type — one of the message types below.
  • edge_node_id and the optional device_id — identify the publisher.

Because the structure is fixed, consumers can subscribe with wildcards like spBv1.0/Plant1/+/# or spBv1.0/+/DDATA/#. Paste them into the topic matcher to check what they match, or read MQTT topics and wildcards for the rules.

Message types

TypePublished byPurpose
NBIRTHEdge NodeAnnounces the node is online; lists all node metrics with names, types and current values
NDEATHEdge Node (via Last Will)Announces the node is offline
DBIRTHEdge NodeAnnounces a device is online, with its full metric list
DDEATHEdge NodeAnnounces a device is offline
NDATA / DDATAEdge NodeChanged values for node or device metrics (report by exception)
NCMD / DCMDHost ApplicationCommands to a node or device, e.g. write a setpoint or request a rebirth
STATEHost ApplicationAnnounces whether a Host Application is online

Sparkplug relies on report by exception: after the BIRTH message establishes every metric, DATA messages only carry values that changed. A consumer that joins late, or loses track, can ask for a fresh BIRTH by sending an NCMD that sets the Node Control/Rebirth metric to true.

Session state: NDEATH, bdSeq and seq

The killer feature of Sparkplug is that a host always knows whether data is current. It builds on MQTT's Last Will and Testament:

  1. When the Edge Node connects, it registers an NDEATH message as its will. The will carries a bdSeq (birth/death sequence) metric.
  2. Right after connecting, it publishes NBIRTH with the same bdSeq, followed by a DBIRTH for each device.
  3. If the node drops off, the broker publishes the NDEATH will. The host matches its bdSeq against the last NBIRTH and marks every metric of that node and its devices as stale.

bdSeq increments with each new MQTT session (wrapping at 255), so a late-arriving NDEATH from an old connection is not mistaken for the death of the current one.

Separately, every message an Edge Node publishes carries a seq number from 0 to 255. NBIRTH starts at 0 and each following message increments it, wrapping back to 0 after 255. If a host sees a gap, it knows a message was lost and can request a rebirth.

The Primary Host Application and STATE

Data is only useful if someone is recording it. A Primary Host Application publishes a retained STATE message (and registers an offline STATE as its will). Edge Nodes configured with a primary host wait for it to be online before publishing their births, and if it goes offline they disconnect and can store data locally or fail over to another MQTT server until it returns. In Sparkplug 3.0 the topic is spBv1.0/STATE/<host_id> with a small JSON payload:

spBv1.0/STATE/scada-main
{ "online": true, "timestamp": 1760140800000 }

Older 2.x deployments used the topic STATE/<host_id> with a plain ONLINE/OFFLINE string.

Protobuf payloads

Sparkplug B payloads are encoded with Google Protocol Buffers. A payload has a timestamp, a seq and a list of metrics. Each metric has a name, a datatype, a value, an optional timestamp and an optional numeric alias. Aliases are declared in the BIRTH; DATA messages can then send the alias instead of the full name, which keeps messages compact.

A DDATA payload, decoded
timestamp: 1760140800123
seq: 17
metrics {
  alias: 4            # "Press-3/Hydraulic/Pressure" in DBIRTH
  timestamp: 1760140800120
  datatype: Float
  float_value: 182.4
}

Binary encoding makes payloads small, which matters on constrained links; you can estimate packet sizes with the MQTT packet size calculator. The downside is that a generic client shows raw bytes. You can still use one to confirm that births and deaths arrive on the right topics:

Watch a Sparkplug namespace in the online client

MQTT settings Sparkplug uses

  • QoS 0 for NBIRTH/DBIRTH, DATA and CMD messages; QoS 1 for the NDEATH will and STATE.
  • Retain false for everything except STATE, which is retained.
  • Clean sessions for Edge Nodes (Clean Session true in 3.1.1, or Clean Start true with a session expiry of 0 in MQTT 5). Sparkplug handles state itself through births and rebirths, so it does not rely on persistent sessions.

Getting started with Eclipse Tahu

Eclipse Tahu is the reference implementation of Sparkplug, with the Protobuf definition and client libraries for Java, C, Python and JavaScript. It handles encoding, aliases and sequence numbers so you can focus on your metrics. The Sparkplug Working Group also publishes a Technology Compatibility Kit (TCK) to test whether implementations follow the spec.

Security considerations

Because Sparkplug commands can write setpoints on real machines, treat access to NCMD and DCMD topics as safety-critical. Use TLS, unique credentials per Edge Node and ACLs that only let each node publish under its own edge_node_id. Our MQTT security best practices cover the details.

Frequently asked questions

What is the difference between MQTT and Sparkplug B?

MQTT is a transport protocol that moves bytes on topics without defining what the topics or payloads mean. Sparkplug B is a specification on top of MQTT that defines a fixed topic namespace, a Protobuf payload format and session state management, so industrial devices and SCADA systems from different vendors can interoperate.

Does Sparkplug B need a special MQTT broker?

No. Sparkplug B works with any MQTT 3.1.1 or MQTT 5 compliant broker that supports QoS, retained messages and Last Will. Some brokers offer optional Sparkplug-aware features, but they are not required for basic operation.

Why are Sparkplug B messages unreadable in my MQTT client?

Sparkplug B payloads are binary Google Protocol Buffers, not JSON or text. A generic MQTT client shows them as raw bytes. You need a Sparkplug-aware tool or a library such as Eclipse Tahu to decode them into metrics.