Tutorials

Node-RED MQTT: Connect, Subscribe and Publish

Use MQTT in Node-RED: configure the broker node, subscribe with mqtt in, publish with mqtt out, parse JSON, set dynamic topics and import a ready-made flow.

Updated · 7 min read

Node-RED and MQTT are a natural pair: MQTT moves messages between devices, and Node-RED lets you wire those messages into dashboards, databases, alerts and APIs without writing a full application. Node-RED ships with two MQTT nodes out of the box — mqtt in and mqtt out — plus a shared broker config node. This tutorial covers all three and ends with a flow you can import.

Run Node-RED

If you do not have Node-RED yet, the quickest options are npm or Docker:

bash
# with Node.js installed
npm install -g --unsafe-perm node-red
node-red

# or with Docker
docker run -it -p 1880:1880 -v node_red_data:/data --name nodered nodered/node-red

Open http://localhost:1880 in your browser. Node-RED is only the client side — you still need a broker. For local development, run Mosquitto in Docker next to it; for a quick test, the public HiveMQ broker works without any setup.

Configure the MQTT broker node

Drag an mqtt in node onto the canvas, double-click it, and click the pencil icon next to Server to create a broker configuration. Every MQTT node that uses the same config node shares one connection.

Tab / fieldWhat to enter
Connection — Server, PortHost name only (for example broker.hivemq.com), port 1883 for plain TCP or 8883 for TLS
Connection — Use TLSEnable for port 8883; add a TLS config with a CA certificate if your broker uses a private CA
Connection — ProtocolMQTT V3.1.1 or MQTT V5
Connection — Client IDLeave blank to auto-generate, or set a unique value
Connection — Keep Alive60 seconds is a sensible default
Security — Username, PasswordYour broker credentials (stored in Node-RED's encrypted credentials file)
Messages — Birth, Close, WillOptional status messages, for example a retained online/offline topic

The Will message on the Messages tab is MQTT's Last Will — see Last Will and Testament. A green connected label under each MQTT node after you deploy means the broker accepted the connection. Not sure which port your broker uses? Check MQTT ports explained.

Subscribe with the mqtt in node

Set the Topic to subscribe to — wildcards are allowed, so testmqtt/nodered-demo/+/telemetry receives telemetry from every room. Each incoming message becomes a Node-RED msg with:

  • msg.payload — the message body
  • msg.topic — the concrete topic it arrived on
  • msg.qos and msg.retain — delivery details

Test your topic filters with the MQTT topic matcher before you deploy. The Output option decides the type of msg.payload:

  • auto-detect (string or buffer) — text becomes a string, binary data stays a Buffer.
  • a parsed JSON object — the node runs JSON.parse for you, so msg.payload.temp is directly usable. Invalid JSON produces an error you can catch with a catch node.
  • auto-detect (parsed JSON object, string or buffer) — parses JSON when possible and falls back to a string.

If you prefer, keep the default output and add a json node after mqtt in; it converts a JSON string to an object and back.

Dynamic subscriptions

Setting the mqtt in node's topic type to Dynamic subscription gives it an input. Send it a message with msg.action set to subscribe (and the topic in msg.topic), unsubscribe, connect or disconnect to control it at runtime — useful when the list of devices changes.

Publish with the mqtt out node

The mqtt out node publishes msg.payload. If the payload is an object, it is converted to a JSON string automatically. Its fields work as fallbacks:

  • Topic — leave it empty to use msg.topic. This is how you publish to dynamic topics, such as one topic per device.
  • QoS and Retain — leave them empty to take msg.qos and msg.retain from the message.

A function node is the simplest way to build the topic per message:

function node
const room = msg.payload.room || 'unknown';
msg.topic = 'testmqtt/nodered-demo/' + room + '/telemetry';
msg.payload = { temp: msg.payload.temp, ts: Date.now() };
msg.qos = 1;
return msg;

Retained status and birth messages

The broker config node can publish a Birth message when it connects, a Close message before a clean disconnect and a Will message if the connection drops. Pointing all three at one retained topic, such as nodered/status with online and offline, gives other systems a reliable way to see whether your Node-RED instance is up. Retained messages are explained in MQTT retained messages.

With the protocol set to MQTT V5, the nodes expose extra options such as message expiry, content type, user properties and the subscription flags No Local, Retain As Published and Retain Handling.

Example flow to import

This flow publishes a random temperature reading every 10 seconds to testmqtt/nodered-demo/room1/telemetry, subscribes to all rooms with JSON parsing enabled, and logs readings above 24 °C to the debug sidebar. Copy it, open the menu, choose Import, paste and deploy.

node-red-mqtt-flow.json
[
  {
    "id": "b1a1c0de00000001",
    "type": "mqtt-broker",
    "name": "HiveMQ public",
    "broker": "broker.hivemq.com",
    "port": "1883",
    "clientid": "",
    "autoConnect": true,
    "usetls": false,
    "protocolVersion": "4",
    "keepalive": "60",
    "cleansession": true
  },
  {
    "id": "b1a1c0de00000002",
    "type": "inject",
    "name": "every 10 s",
    "props": [{ "p": "payload" }],
    "repeat": "10",
    "once": true,
    "onceDelay": "1",
    "payload": "",
    "payloadType": "date",
    "x": 130,
    "y": 80,
    "wires": [["b1a1c0de00000003"]]
  },
  {
    "id": "b1a1c0de00000003",
    "type": "function",
    "name": "build reading",
    "func": "msg.topic = 'testmqtt/nodered-demo/' + 'room1' + '/telemetry';\nmsg.payload = { temp: +(18 + Math.random() * 8).toFixed(1), ts: msg.payload };\nreturn msg;",
    "outputs": 1,
    "x": 320,
    "y": 80,
    "wires": [["b1a1c0de00000004"]]
  },
  {
    "id": "b1a1c0de00000004",
    "type": "mqtt out",
    "name": "publish",
    "topic": "",
    "qos": "1",
    "retain": "false",
    "broker": "b1a1c0de00000001",
    "x": 510,
    "y": 80,
    "wires": []
  },
  {
    "id": "b1a1c0de00000005",
    "type": "mqtt in",
    "name": "subscribe",
    "topic": "testmqtt/nodered-demo/+/telemetry",
    "qos": "1",
    "datatype": "json",
    "broker": "b1a1c0de00000001",
    "nl": false,
    "rap": true,
    "rh": 0,
    "inputs": 0,
    "x": 140,
    "y": 160,
    "wires": [["b1a1c0de00000006"]]
  },
  {
    "id": "b1a1c0de00000006",
    "type": "switch",
    "name": "temp > 24",
    "property": "payload.temp",
    "propertyType": "msg",
    "rules": [{ "t": "gt", "v": "24", "vt": "num" }],
    "checkall": "true",
    "outputs": 1,
    "x": 330,
    "y": 160,
    "wires": [["b1a1c0de00000007"]]
  },
  {
    "id": "b1a1c0de00000007",
    "type": "debug",
    "name": "too warm",
    "active": true,
    "tosidebar": true,
    "complete": "true",
    "x": 510,
    "y": 160,
    "wires": []
  }
]

Watch the same messages from outside Node-RED to confirm they really hit the broker:

Watch your Node-RED messages live

Troubleshooting

  • Stuck on connecting — wrong port or TLS setting, or the Server field contains mqtt://. Enter only the host name.
  • Connects, then disconnects in a loop — another client uses the same client ID, often a second Node-RED instance with a copied flow. Clear the field.
  • No messages arrive — the subscription topic does not match the publish topic (case matters), or an ACL on the broker denies it. More in the MQTT connection errors guide.

Moving logic out of Node-RED into a script later? The MQTT code generator generates client code for your own broker settings in Python, JavaScript and more, and the online MQTT client is handy for poking at topics while you build flows.

Frequently asked questions

Does Node-RED include an MQTT broker?

No. Node-RED ships MQTT client nodes (mqtt in and mqtt out) but not a broker. You connect them to an existing broker such as Mosquitto, EMQX, a managed broker or a public test broker. Community add-on nodes can embed a broker, but a separate broker is the usual setup.

How do I set the MQTT topic dynamically in Node-RED?

Leave the Topic field of the mqtt out node empty and set msg.topic in a previous node, such as a change or function node. The node then publishes each message to the topic in msg.topic. QoS and retain can likewise come from msg.qos and msg.retain.

Why does my Node-RED MQTT node show disconnected?

Check the broker config node: the host, port and TLS setting must match the broker listener, credentials go on the Security tab, and the client ID must be unique or blank. Two nodes or instances with the same client ID will keep disconnecting each other.