Skip to content
NEW AI Solution Creator — get a working IoT prototype in 10 minutes
Stand with Ukraine flag

MQTT Integration

MQTT Integration connects ThingsBoard to any MQTT broker — cloud or on-premises — and subscribes to one or more topic filters. The platform:

  • subscribes to configured topics on the external broker,
  • passes each received message through the Uplink Converter (JavaScript or TBEL),
  • decodes the payload and maps it to ThingsBoard telemetry and attributes,
  • auto-creates devices on the first uplink.

When to use MQTT Integration:

  • Devices already publish to an existing MQTT broker (HiveMQ, Mosquitto, AWS IoT Core, etc.) and you want to ingest that data into ThingsBoard without re-flashing firmware.
  • You need to bridge two MQTT brokers — one for devices, one for ThingsBoard.
  • You want to send commands back to devices via MQTT downlink topics.
  • You need topic-based device routing: device name or type is encoded in the topic path rather than the payload.

Before creating the integration, ensure:

  • You have access to ThingsBoard Cloud with integration functionality enabled for your tenant.
  • You have permissions to create integrations and data converters.
  • You know the MQTT broker host, port, and any credentials required to connect.
  • You know the topic structure your devices publish to and the structure of their payloads.

The uplink converter decodes each MQTT message payload — received as an array of bytes — and maps it to ThingsBoard’s data model: it resolves the target device and extracts fields into telemetry and attributes.

For the full decoder function reference — all input parameters and output fields — see Uplink data converter.

  1. Go to Integrations center ⇾ Data converters.
  2. Click + Add data converter ⇾ Create new converter.

In the Add data converter dialog:

  1. Converter type — leave Uplink (selected by default).
  2. Integration type — in the search field, enter MQTT and select MQTT from the list.
  3. Name — enter a converter name, for example MQTT Uplink Converter.
  4. Main decoding configuration — a code editor with the function signature function decoder(payload, metadata) {.
    By default it opens in TBEL; use the TBEL / JS toggle (upper right) to switch languages.

    The default template handles both patterns: device name and type from the JSON payload (if present), or extracted from the MQTT topic as a fallback. Adapt field names to match your device.

    // Decode an uplink message from a buffer
    // payload - array of bytes
    // metadata - key/value object
    /** Decoder **/
    // decode payload to JSON
    var data = decodeToJson(payload);
    // --- Device name and type ---
    // Extract from MQTT topic (e.g. "my/topic/deviceType/deviceName")
    var topicParts = metadata['topic'] != null ? metadata['topic'].split('/') : null;
    var deviceName = data.deviceName != null ? data.deviceName :
    (topicParts != null && topicParts.length > 0 ? topicParts[topicParts.length - 1] : 'Unknown Device');
    var deviceType = data.deviceType != null ? data.deviceType :
    (topicParts != null && topicParts.length > 1 ? topicParts[topicParts.length - 2] : 'default');
    // var customerName = 'Customer C';
    // var groupName = 'thermostat devices';
    // use assetName and assetType instead of deviceName and deviceType
    // to automatically create assets instead of devices.
    // var assetName = 'Asset A';
    // var assetType = 'building';
    // --- Timestamp parsing ---
    var timestamp = -1;
    if (data.ts != null) {
    timestamp = data.ts;
    } else if (data.timestamp != null) {
    timestamp = new Date(data.timestamp).getTime();
    }
    if (timestamp == -1) {
    timestamp = Date.now();
    }
    // --- Telemetry and attributes ---
    var telemetry = {};
    var attributes = {
    model: 'Model A',
    serialNumber: 'SN111',
    integrationName: metadata['integrationName'],
    };
    // Keys to exclude from telemetry (already used or non-telemetry fields)
    var excludeFromTelemetryList = ["deviceName", "deviceType", "ts", "timestamp"];
    // Parse all remaining JSON fields as telemetry
    telemetry.putAll(toFlatMap(data, excludeFromTelemetryList, true));
    // Result object with device attributes/telemetry data
    var result = {
    deviceName: deviceName,
    deviceType: deviceType,
    // customerName: customerName,
    // groupName: groupName,
    // assetName: assetName,
    // assetType: assetType,
    attributes: attributes,
    telemetry: {
    ts: timestamp,
    values: telemetry
    }
    };
    /** Helper functions 'decodeToString', 'decodeToJson' and 'toFlatMap' are already built-in **/
    return result;
  5. Click Add.

Converter input variables

ThingsBoard passes two variables to the decoder. Function signature: function decoder(payload, metadata): object | object[]

VariableTypeDescription
payloadbyte arrayThe MQTT message body. Use the built-in helper functions to decode it to a string or JSON object.
metadata{[key: string]: string}Key/value map with integration-specific fields. For MQTT, the most important field is topic — the full MQTT topic of the incoming message (e.g. tb/sensors/thermostat/SN-001). Additional fields can be configured in the integration details.

Metadata keys available in the MQTT converter:

KeyExample valueDescription
topictb/sensors/thermostat/SN-001The full MQTT topic the message was received on
integrationNameMQTT integrationName of the integration as configured in ThingsBoard

To work with the payload, use the built-in helper functions:

FunctionResult
decodeToJson(payload)Parse bytes as JSON → return a JS object
decodeToString(payload)Convert bytes to a string (UTF-8)
toFlatMap(obj, excludeKeys, flatNested)Flatten nested JSON into a flat key/value map

For common scripting patterns — renaming fields, extracting nested values, normalizing data, and handling non-JSON payloads — see Uplink data converter: Common scripting patterns.

Testing the converter in the editor

Click the Test decoder function button below the editor — the Test decoder function (TBEL) dialog opens with four panels.

Fill in the fields:

Payload content type: Json

Payload content:

{
"deviceName": "SN-001",
"deviceType": "thermostat",
"humidity": 60,
"temperature": 22.5
}

Metadata — two rows (key / value):

KeyValue
topictb/sensors/thermostat/SN-001
integrationNameMQTT integration

Click Test — in the Output panel you should see:

{
"deviceName": "SN-001",
"deviceType": "thermostat",
"attributes": {
"model": "Model A",
"serialNumber": "SN111",
"integrationName": "MQTT integration"
},
"telemetry": {
"ts": 1780055515934,
"values": {
"humidity": 60,
"temperature": 22.5
}
}
}

Make sure deviceName is not empty and telemetry.values contains the expected keys. If Output is empty or shows an error, check the converter code in the Decoder panel.

After a successful test, click Add to save the converter.

  1. Go to Integrations center ⇾ Integrations and click + Add integration.
  2. Basic settings:
    • Select MQTT as the integration type.
    • Enter a Name for the integration, or keep the default MQTT integration.
    • Enable integration and Allow create devices or assets are enabled by default.
    • Click Next.
  3. Uplink data converter:
    • Click Select existing and choose the MQTT Uplink Converter created in the previous step, or click Create new to define the decoder inline.
    • Click Next.
  4. Downlink data converter:
    • Click Skip — a downlink converter is only needed when ThingsBoard must send commands back to the device over MQTT. It can be configured later.
  5. Connection:
    • Enter the MQTT broker Host and Port (e.g. broker.hivemq.com, port 1883).
    • Select the appropriate Credentials type and fill in the required fields (e.g. Anonymous).
    • Configure the Topic filters — at least one topic filter is required (e.g. tb/sensors/thermostat/SN-001, QoS 0 — At most once).
    • Optionally, expand Advanced settings to configure protocol version, client ID, and other parameters.
    Read more about each parameter in Connection settings.
  6. Click Check connection to verify the broker is reachable, then click Add to complete the integration setup.

Host

Hostname or IP address of the MQTT broker ThingsBoard should connect to.

Example: broker.hivemq.com

Port

TCP port of the MQTT broker. Common values:

PortUsage
1883Unencrypted MQTT
8883MQTT over TLS/SSL

Credentials

ThingsBoard supports three credential types for authenticating with the broker.

Anonymous — no credentials sent. Use only with brokers that allow unauthenticated connections.

Basic — username and password authentication.

FieldDescription
UsernameMQTT username
PasswordMQTT password

PEM — certificate-based mutual TLS authentication. Required when the broker enforces client certificate verification.

FieldDescription
CA certificate fileThe CA certificate that signed the broker’s server certificate. ThingsBoard uses it to verify the broker’s identity on connect.
Certificate fileThe client certificate presented to the broker when mutual TLS is required.
Private key fileThe private key corresponding to the client certificate.
Private key passwordPassword for the private key, if encrypted.

Each file can be uploaded directly (Browse file) or retrieved from ThingsBoard’s secret storage (Use Secret storage).

To generate a client certificate and private key signed by your CA:

Terminal window
openssl req -newkey rsa:2048 -keyout client_key.pem -out client.csr \
-nodes -subj "/CN=thingsboard-integration"
openssl x509 -req -in client.csr -CA ca.pem -CAkey ca_key.pem \
-CAcreateserial -out client.pem -days 3650

Upload ca.pem as CA certificate file, client.pem as Certificate file, and client_key.pem as Private key file.

Enable SSL

When enabled, ThingsBoard establishes a TLS-encrypted connection to the broker. Enable this when using port 8883 or any broker that requires encrypted transport. For PEM credentials, SSL is implicitly required.

Topic Filters

One or more MQTT topic subscriptions. ThingsBoard subscribes to all configured topics simultaneously on connection.

FieldDescription
TopicMQTT topic filter string
QoSQuality of Service level for the subscription

Wildcard support:

WildcardScopeExampleMatches
+Single levelv1/devices/+/telemetryv1/devices/SN-001/telemetry, v1/devices/SN-002/telemetry
#Multi-level (must be last)v1/devices/me/#v1/devices/me/telemetry, v1/devices/me/attributes/request/1

QoS levels:

LevelNameDelivery guarantee
0At most onceFire-and-forget. Message may be lost.
1At least onceAcknowledged delivery. Message may be duplicated.
2Exactly onceGuaranteed single delivery. Highest overhead.

Click Add topic filter to subscribe to additional topics.

Execute Remotely

When enabled, ThingsBoard generates an Integration key and Integration secret. These credentials allow the integration to run as a separate process outside the ThingsBoard cluster — useful when the integration must reach a broker not accessible from the ThingsBoard server (e.g., in a private network or on-premises environment).

See Remote Integration for setup details.

Advanced Settings

ParameterDefaultDescription
Protocol versionMQTT 3.1.1MQTT protocol version used for the connection. Options: MQTT 3.1, MQTT 3.1.1, MQTT 5.0. Match this to the version your broker supports.
Clean sessiononWhen on, ThingsBoard starts with a fresh session on each connect — no queued messages from previous sessions are delivered. When off, the broker delivers messages published while the client was disconnected (requires QoS 1 or 2).
RetainedoffWhen on, downlink messages published to the broker are marked as retained.
Downlink QoS1Quality of Service level for all downlink PUBLISH messages. Fixed at QoS 1 (at least once) — not configurable.
Client IDauto-generatedMQTT client identifier sent to the broker. Leave empty for an auto-generated ID. If set manually, ensure it is unique — most brokers reject or disconnect duplicate client IDs.
Max bytes in message32368Maximum size of a single MQTT message payload in bytes. Messages exceeding this limit are discarded.
Connection timeout (sec)10Seconds to wait for the broker to accept the connection before the attempt is considered failed.
Downlink topic pattern${topic}Topic used when publishing downlink messages to the device. Placeholders like ${topic} are resolved from the downlink converter’s output metadata — metadata.topic sets the actual publish topic. Can be set to a fixed topic string or any metadata variable pattern.
DescriptionOptional free-text description of the integration.
MetadataOptional key–value pairs attached to the integration. These values are injected into every message processed by the integration and are accessible in converter scripts via the metadata object.

ThingsBoard retransmits unacknowledged MQTT packets — PUBLISH (QoS 1/2), SUBSCRIBE, UNSUBSCRIBE, and PUBREL — using exponential backoff: the delay doubles with each attempt, and a jitter factor adds random variance to prevent synchronized retries.

Example: 3 attempts, 5,000 ms initial delay, jitter factor 0.15 → retries at approximately 5,000 ms, 10,000 ms, and 20,000 ms (each ±15%). If the final attempt goes unacknowledged, the message is dropped and the Rule Engine routes it via the Failure chain.

After the integration is created, send a test uplink and confirm that ThingsBoard received the message, decoded it correctly, and provisioned the device.

Test the integration by publishing a message to the configured topic using mosquitto_pub or any MQTT client. Replace broker.hivemq.com and the topic (tb/sensors/thermostat/SN-001) with your actual values.

Terminal window
mosquitto_pub -h broker.hivemq.com -p 1883 \
-t "tb/sensors/thermostat/SN-001" \
-m '{"temperature":25.1}'

If the broker requires Basic authentication, add credentials:

Terminal window
mosquitto_pub -h broker.hivemq.com -p 1883 \
-u "YOUR_USERNAME" -P "YOUR_PASSWORD" \
-t "tb/sensors/thermostat/SN-001" \
-m '{"temperature":25.1}'

Go to Integrations center ⇾ Integrations, open MQTT integration, and click the Events tab. Each successfully processed uplink appears as a row with status OK.

Click ⋅⋅⋅ in the Message column to see the raw MQTT topic and payload received by the integration.

To inspect converter processing, go to Integrations center ⇾ Data converters, click MQTT Uplink Converter, and open its Events tab:

  • In shows the raw payload passed to the converter, including the MQTT topic in metadata
  • Out shows the decoded result (deviceName, deviceType, attributes, telemetry)
  • Metadata contains the MQTT topic and integration name

Go to Entities ⇾ Devices — device SN-001 is provisioned automatically on the first uplink. Open it and check the Latest telemetry tab to confirm temperature = 25.1.

Scenario A: Device name and type from JSON payload

Use when every MQTT message contains deviceName and deviceType fields. This is the simplest pattern — device identity is fully self-contained in the payload.

Input payload (published to any topic):

{
"deviceName": "Thermometer",
"deviceType": "thermostat",
"model": "SN-001",
"temperature": 33
}

Converter:

/** Decoder **/
var data = decodeToJson(payload);
var deviceName = data.deviceName;
var deviceType = data.deviceType;
var result = {
deviceName: deviceName,
deviceType: deviceType,
attributes: {
model: data.model,
integrationName: metadata['integrationName'],
},
telemetry: {
temperature: data.temperature
}
};
/** Helper function 'decodeToJson' is already built-in **/
return result;

Field mapping:

JSON fieldOutput fieldTypeNotes
deviceNamedeviceNameDevice identifier; auto-creates the device on first uplink
deviceTypedeviceTypeDevice profile name
modelmodelattribute
temperaturetemperaturetelemetry

For the payload above the decoder produces:

{
"deviceName": "Thermometer",
"deviceType": "thermostat",
"attributes": {
"model": "SN-001",
"integrationName": "Test MQTT"
},
"telemetry": {
"temperature": 33
}
}

To adapt this converter to your device:

  • Device name from a different field — replace data.deviceName with the field that carries the device identifier in your payload.
  • Hardcoded device type — replace data.deviceType with a string literal (e.g. 'thermostat') if all devices share the same profile.
  • Rename a field — use outputName: data.sourceField to store the value under a different key in ThingsBoard.
  • Additional telemetry fields — extend the telemetry object with more fields from the payload.

Scenario B: Device name and type from the MQTT topic

Use when devices publish minimal payloads — sensor readings only — and embed their identity in the topic path. This is common for constrained devices that cannot include metadata in every message.

Topic structure: tb/mqtt-integration-tutorial/sensors/{deviceName}

Example topic: tb/mqtt-integration-tutorial/sensors/SN-001

Input payload (published to the topic above):

{
"temperature": 25.1
}

Converter:

/** Decoder **/
// decode payload to string
var payloadStr = decodeToString(payload);
var data = JSON.parse(payloadStr);
// Topic: tb/mqtt-integration-tutorial/sensors/{deviceName}
// Index: 0 1 2 3
var deviceName = metadata.topic.split("/")[3];
var deviceType = 'sensor'; // hardcoded device profile
// Result object with device attributes/telemetry data
var result = {
deviceName: deviceName,
deviceType: deviceType,
attributes: {
integrationName: metadata['integrationName'],
},
telemetry: {
temperature: data.temperature,
}
};
/** Helper functions 'decodeToString' and 'decodeToJson' are already built-in **/
return result;

Field mapping:

SourceOutput fieldTypeNotes
metadata.topic.split("/")[3]deviceName4th segment of the topic path (0-indexed)
hardcoded 'sensor'deviceTypeDevice profile name
data.temperaturetemperaturetelemetryFrom JSON payload
metadata['integrationName']integrationNameattributeName of the integration

For the message published to tb/mqtt-integration-tutorial/sensors/SN-001 with payload {"temperature": 25.1} the decoder produces:

{
"deviceName": "SN-001",
"deviceType": "sensor",
"attributes": {
"integrationName": "MQTT integration"
},
"telemetry": {
"temperature": 25.1
}
}

To adapt this converter to your topic structure:

  • Different topic depth — change the index in split("/")[3] to match the position of the device identifier in your topic path (e.g. split("/")[2] for a 3-segment topic).
  • Device type from topic — replace the hardcoded 'sensor' with another segment, e.g. metadata.topic.split("/")[2], if your topic encodes the device type.
  • Device name from payload — replace metadata.topic.split("/")[3] with a field from data (e.g. data.deviceId) if the device name is in the payload body.
  • Additional telemetry fields — extend the telemetry object with more fields from the payload (e.g. humidity: data.humidity).
  • Wildcard subscription — when using tb/mqtt-integration-tutorial/sensors/+ as the topic filter, the + segment is preserved in metadata.topic and accessible via split("/").

Scenario C: Nested JSON + toFlatMap for automatic flattening

Use when the payload has a nested structure and you want to automatically map all remaining fields to telemetry without listing each one explicitly. toFlatMap traverses the object recursively and produces dot-separated keys for nested fields. Fields listed in excludeKeys are skipped.

Input payload:

{
"deviceName": "air-monitor-X",
"deviceType": "air-quality",
"meta": { "source": "cloud" },
"sensors": {
"co2": 412,
"pm25": 8.2,
"voc": 0.3
},
"location": {
"lat": 50.45,
"lon": 30.52
},
"ts": 1700000000000
}

Converter:

/** Decoder **/
var data = decodeToJson(payload);
// Fields to exclude from telemetry — used as device identity, attributes, or timestamp
var excludeKeys = ['deviceName', 'deviceType', 'ts', 'meta', 'location'];
// Flatten all remaining fields into telemetry (nested objects become dot-separated keys)
var telemetry = {};
telemetry.putAll(toFlatMap(data, excludeKeys, true));
var result = {
deviceName: data.deviceName,
deviceType: data.deviceType,
attributes: {
latitude: data.location.lat,
longitude: data.location.lon,
source: data.meta.source,
integrationName: metadata['integrationName']
},
telemetry: {
ts: data.ts != null ? data.ts : Date.now(),
values: telemetry
}
};
/** Helper functions 'decodeToString', 'decodeToJson' and 'toFlatMap' are already built-in **/
return result;

Field mapping:

JSON fieldOutput fieldTypeNotes
deviceNamedeviceNameExcluded from telemetry via excludeKeys
deviceTypedeviceTypeExcluded from telemetry via excludeKeys
location.latlatitudeattributeExtracted manually before flattening
location.lonlongitudeattributeExtracted manually before flattening
meta.sourcesourceattributeExtracted manually before flattening
sensors.co2sensors.co2telemetryAuto-mapped by toFlatMap
sensors.pm25sensors.pm25telemetryAuto-mapped by toFlatMap
sensors.vocsensors.voctelemetryAuto-mapped by toFlatMap
tstsTimestamp in milliseconds; excluded from telemetry via excludeKeys

For the payload above the decoder produces:

{
"deviceName": "air-monitor-X",
"deviceType": "air-quality",
"attributes": {
"latitude": 50.45,
"longitude": 30.52,
"source": "cloud",
"integrationName": "MQTT integration"
},
"telemetry": {
"ts": 1700000000000,
"values": {
"sensors.co2": 412,
"sensors.pm25": 8.2,
"sensors.voc": 0.3
}
}
}

To adapt this converter to your device:

  • Different nested structure — update excludeKeys to include any top-level fields you do not want in telemetry.
  • Rename auto-mapped keys — extract the field manually before calling toFlatMap and add it to excludeKeys so it is not duplicated.
  • No timestamp in payload — replace the conditional with ts: Date.now() directly.
  • Timestamp in seconds — convert before assigning: ts: data.ts * 1000.

Scenario D: String payload (not JSON)

Use when the device sends raw text instead of JSON — for example a semicolon-delimited string. decodeToString converts the byte array to a UTF-8 string; the converter then parses it manually using split or any other string method.

Input payload (text/plain):

sensor-001;23.5;60;87

Converter:

/** Decoder **/
// Decode bytes to a UTF-8 string and split by delimiter
var raw = decodeToString(payload);
var parts = raw.trim().split(';');
// parts[0] = device name
// parts[1] = temperature
// parts[2] = humidity
// parts[3] = battery
var result = {
deviceName: parts[0],
deviceType: 'csv-sensor',
attributes: {
integrationName: metadata['integrationName'],
topic: metadata['topic']
},
telemetry: {
ts: Date.now(),
values: {
temperature: parseFloat(parts[1]),
humidity: parseFloat(parts[2]),
battery: parseInt(parts[3])
}
}
};
/** Helper function 'decodeToString' is already built-in **/
return result;

Field mapping:

PositionOutput fieldTypeNotes
parts[0]deviceNameFirst segment used as the device identifier
'csv-sensor'deviceTypeHardcoded device profile
parts[1]temperaturetelemetryParsed as float
parts[2]humiditytelemetryParsed as float
parts[3]batterytelemetryParsed as integer

For the payload sensor-001;23.5;60;87 the decoder produces:

{
"deviceName": "sensor-001",
"deviceType": "csv-sensor",
"attributes": {
"integrationName": "MQTT integration",
"topic": "tb/sensors/csv/sensor-001"
},
"telemetry": {
"ts": 1780299924174,
"values": {
"temperature": 23.5,
"humidity": 60.0,
"battery": 87
}
}
}

To adapt this converter to your device:

  • Different delimiter — replace ';' in split(';') with the delimiter your device uses (e.g. ',', '|', ' ').
  • Device name from topic instead of payload — replace parts[0] with metadata['topic'].split('/').pop().
  • Timestamp in the string — parse it from the appropriate position and assign to ts; convert to milliseconds if the device sends seconds.
  • Fewer or more fields — add or remove entries in the values object and update the index comments.

Downlink allows ThingsBoard to send commands back to the device over MQTT in response to a Rule Engine event — for example, when a shared attribute is updated. ThingsBoard publishes the encoded payload to the topic defined by the Downlink topic pattern in the integration’s Advanced settings (default: ${topic}, resolved from metadata.topic in the downlink converter output).

The downlink converter transforms a Rule Engine message into an MQTT payload. For the full encoder function reference, see Downlink data converter.

When downlink is needed

  • You need to send configuration updates or commands to the device (e.g., set a threshold, change a polling interval).
  • You want to acknowledge received data with a control response published to a device-specific topic.

The encoder receives msg, metadata, and msgType, and must return:

  • contentTypeJSON, TEXT, or BINARY
  • data — the payload string to publish
  • metadata.topic — when the integration’s Downlink topic pattern is ${topic}, the integration publishes to this topic

For RPC commands, msg.method and msg.params are available. msg.params is always a string — use parseFloat(msg.params) or JSON.parse(msg.params) when a numeric or structured value is needed. See the Downlink data converter reference for the full encoder API.

  1. Go to Integrations center ⇾ Integrations and open the MQTT Integration.
  2. Click the pencil icon to enter edit mode.
  3. In the Downlink data converter field, click Create new.
  4. Enter a name (e.g. MQTT Downlink Converter) and paste the encoder script.
  5. Click Add, then click Apply changes.

The encoder function used in this tutorial:

/** Encoder **/
// Publish the ThingsBoard message as JSON to the device command topic.
// metadata.topic is read by the integration when Downlink topic pattern is ${topic}.
var result = {
contentType: "JSON",
data: JSON.stringify(msg),
metadata: {
topic: metadata['deviceType']+'/'+metadata['deviceName']+'/upload'
}
};
return result;

To ensure the downlink converter has access to device information, we enrich message metadata with the device name and device profile name. These values are later used by the MQTT integration downlink converter to dynamically build the MQTT topic (for example, thermostat/SN-001/upload) and other payload fields.

  1. Go to Rule chains ⇾ Root Rule Chain.
  2. In the Enrichment section of the node library, find the originator fields node and drag it onto the canvas.
  3. In the originator fields node configuration, map the source fields:
    • Name ⇾ deviceName
    • Profile name ⇾ deviceType
    • Then click Add.
  4. Connect the message type switch node to the originator fields node using the Attributes Updated and Post attributes link types.
  5. In the node library, find the integration downlink node and drag it onto the canvas.
  6. In the node configuration, set a name (e.g., MQTT integration) and select your MQTT integration. Click Add.
  7. Connect the originator fields node to the integration downlink node using the Success relation.
  8. Click Apply changes.

When a shared attribute is created or updated, the Rule Engine routes the event to the integration, which publishes the encoded payload to the downlink topic.

Subscribe to the downlink topic with your MQTT client to verify receipt:

Terminal window
mosquitto_sub -h broker.hivemq.com -p 1883 -t "thermostat/SN-001/upload"

Trigger a downlink by adding a shared attribute to the device:

  1. Go to Entities ⇾ Devices, open SN-001, and navigate to the Attributes tab.
  2. Select Shared attributes, click + to add a new attribute.
  3. Set the key (e.g. powerState) and value (e.g. on).
  4. Click Add.

The Rule Engine routes the attribute update to the integration downlink node, which passes it to the encoder. The terminal subscribed to SN-001/commands will print the downlink payload:

{"powerState":"on"}

To inspect the exchange, open the downlink converter’s Events tab:

  • In shows the Rule Engine message
  • Out shows the encoded MQTT payload
  • Metadata shows the topic and integration name.
SymptomCauseFix
Integration status shows Disconnected (broker unreachable)Wrong host, port, or firewall blocking the connectionVerify host, port, and firewall rules; use Check connection in the integration settings
Integration status shows Disconnected (authentication failure)Wrong credentialsCheck username/password or certificate files; ensure the credentials type matches the broker configuration
Integration status shows Disconnected (SSL mismatch)TLS setting doesn’t match brokerEnable or disable Enable SSL to match the broker’s TLS requirement; check that port matches (1883 for plain, 8883 for TLS)
Messages received but device not createddeviceName is empty or undefinedCheck Debug Events → Out on the converter; ensure deviceName is resolved from the payload or topic
Messages received but telemetry not savedConverter returns {} or []Ensure telemetry.values contains at least one field
No messages received at allTopic filter does not match published topicVerify the topic filter in the integration settings; check wildcard syntax
Error in converterJavaScript or TBEL exceptionOpen Events → Error on the converter and inspect the stack trace
Data present but timestamp is wrongDevice sends ts in secondsConvert before assigning: ts: data.ts * 1000
Duplicate messagesQoS 1 or 2 with Clean session off after reconnectEnable Clean session in Advanced settings to discard queued messages on reconnect
Multiple connections rejected by brokerDuplicate Client IDLeave Client ID empty for auto-generated IDs, or ensure the configured ID is unique per broker

How to read Debug Events

  1. Go to Integrations center ⇾ Integrations, open your integration, and click the Events tab. Filter by Uplink.
  2. Click on an event to inspect:
  • In — what the integration received: the raw MQTT payload and metadata including the topic
  • Out — what the converter returned: the decoded device name, attributes, and telemetry
  • Error — error text, if any
  • Integrations Overview — how ThingsBoard connects to external platforms and how uplink/downlink flow works
  • Uplink Data Converter — full decoder function reference: input parameters, output fields, and scripting patterns
  • Downlink Data Converter — full encoder function reference for sending commands to devices
  • Remote Integration — run the integration outside the ThingsBoard server to reach MQTT brokers in a private network
  • TBEL scripting reference — built-in functions and operators for writing converter scripts
  • Rule Engine — how uplink messages are processed after the converter
  • MQTT one-way RPC — send a one-way RPC command from ThingsBoard to a device over MQTT with no response expected
  • MQTT two-way RPC — send an RPC command from ThingsBoard to a device over MQTT and receive the response back