Tutorials

MQTT Automations with n8n: Trigger, Publish and Build Workflows

Connect n8n to an MQTT broker: configure credentials, use the MQTT Trigger and MQTT nodes, parse JSON, route alerts and publish commands from workflows.

Updated · 8 min read

MQTT Automations with n8n: Trigger, Publish and Build Workflows

n8n talks to MQTT through two core nodes: the MQTT Trigger, which subscribes to topics and starts a workflow for every incoming message, and the MQTT node, which publishes messages from any step of a workflow. Add an MQTT credential with your broker's host, port and login, drop in a trigger, activate the workflow and every sensor reading can fan out to Slack, email, a database, an HTTP API or back to a device.

This tutorial builds two real workflows — a temperature alert and a webhook-to-device command — and shows how to test each step with a second MQTT client.

How n8n fits into an MQTT system

n8n is a workflow automation tool, not a broker. It connects to your broker as an ordinary MQTT client:

Rolen8n pieceMQTT action
React to device dataMQTT Trigger nodeSUBSCRIBE to one or more topic filters
Send commands or derived dataMQTT nodePUBLISH to a topic
GlueAny other node (IF, Switch, HTTP Request, Code, Slack…)—

That means everything you know about MQTT clients applies: each trigger needs a unique client ID, QoS is negotiated per subscription, and the broker's ACLs decide what n8n may read and write. If you already use Node-RED, the model is similar; see Node-RED and MQTT for the comparison point. n8n's strength is the long list of SaaS integrations sitting next to the MQTT nodes.

Run n8n locally

The quickest way to experiment is the official Docker image:

Start n8n on http://localhost:5678
docker volume create n8n_data
docker run -it --rm --name n8n \
  -p 5678:5678 \
  -v n8n_data:/home/node/.n8n \
  docker.n8n.io/n8nio/n8n

Open http://localhost:5678, create the owner account and start a new workflow. n8n Cloud works the same way; the only difference is that the broker must be reachable from the internet, because the MQTT connection is opened from n8n's servers, not from your laptop.

Create the MQTT credential

Add any MQTT node, open Credential to connect with and choose Create new credential. The MQTT credential has these important fields:

FieldValue for a TCP testValue for TLS
Protocolmqttmqtts
Hostbroker.connectmq.combroker.connectmq.com
Port18838883
Username / Passwordyour broker credentialsyour broker credentials
Client IDleave empty or set a unique valuesame
Clean Sessiononon

Use TLS (mqtts on 8883) for anything beyond a quick test: the credential is stored once and reused by every node, so there is no reason to send passwords in clear text. n8n tests the connection when you save — if it fails, the error text is usually the broker's CONNACK reason. Look it up in the MQTT reason codes tool.

Workflow 1: temperature alert

The first workflow listens for sensor readings and posts a message when a value crosses a threshold.

Step 1 — MQTT Trigger. Set Topics to testmqtt/n8n/+/temperature. The field accepts a comma-separated list, and the + and # wildcards work as usual (check your filters with the topic matcher). Under Options, enable JSON Parse Body so the payload is parsed into an object, and enable Only Message if you do not need the topic in later steps. Keep the topic when one workflow handles many devices.

With both options as shown, a message arrives as an item like this:

Trigger output (JSON Parse Body on, Only Message off)
{
  "topic": "testmqtt/n8n/greenhouse-1/temperature",
  "message": { "value": 31.4, "unit": "C", "ts": 1760700000 }
}

Step 2 — IF node. Add a condition: number {{ $json.message.value }} is larger than 30.

Step 3 — Notify. On the true branch add a Slack, Telegram, Discord or Send Email node. A useful message text is:

Notification text (n8n expression)
🌡 {{ $json.topic.split('/')[2] }} is at {{ $json.message.value }} °{{ $json.message.unit }}

The split('/')[2] picks the device ID out of the topic, which is why a consistent layout pays off — see topic design best practices.

Test it before activating

Click Execute workflow (or Listen for test event on the trigger). The trigger now waits for one message. Publish a reading from a terminal or from the online MQTT client:

Send a test reading
mosquitto_pub -h broker.connectmq.com -p 1883 \
  -t testmqtt/n8n/greenhouse-1/temperature \
  -m '{"value": 31.4, "unit": "C", "ts": 1760700000}'

The workflow executes once and you can inspect the data on every node. Publish a second message with "value": 22 to confirm the false branch stays silent.

Workflow 2: webhook to device command

The opposite direction is just as common: something outside the MQTT world (a form, a calendar, a CRM event, another API) should switch a device.

  1. Webhook node, method POST, path lamp. Its test URL looks like http://localhost:5678/webhook-test/lamp.
  2. IF node that checks a shared secret header, for example {{ $json.headers['x-api-key'] }} equals a value you store in n8n — do not let anyone on the internet publish to your devices.
  3. MQTT node with Topic testmqtt/n8n/lamp-1/set. Turn Send Input Data off and set Message to {{ $json.body.state }}. Under options choose QoS 1, and leave Retain off for momentary commands.

With Send Input Data on, n8n publishes the whole input item as JSON — handy for forwarding, but usually too much for a device that expects ON or OFF.

Watch the command topic in one terminal and call the webhook in another:

Terminal 1 — watch what n8n publishes
mosquitto_sub -h broker.connectmq.com -p 1883 -t 'testmqtt/n8n/+/set' -v
Terminal 2 — trigger the workflow
curl -X POST http://localhost:5678/webhook-test/lamp \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: change-me' \
  -d '{"state": "ON"}'

Terminal 1 should print testmqtt/n8n/lamp-1/set ON. For the reverse pattern — MQTT messages that call an HTTP endpoint — see MQTT to webhook.

Activate the workflow

Test executions only run while the editor is listening. To process messages permanently, save the workflow and activate (publish) it. From then on n8n keeps the subscription open in the background and every message creates an execution you can review in the executions list.

Two settings matter once traffic is real:

  • Execution volume. Every message is one execution. A sensor publishing once per second creates 86,400 executions a day, which fills the execution history and costs CPU. Aggregate at the edge, publish less often, or subscribe to an "events" topic rather than raw telemetry.
  • Ordering. The trigger processes messages in parallel by default. If order matters (state changes for the same device), turn parallel processing off in the trigger options so messages are handled one after another.

Delivery guarantees and restarts

n8n is a client, so its delivery guarantees are the broker's guarantees for that subscription:

  • QoS 0 messages published while n8n is restarting are lost.
  • QoS 1 with a persistent session (Clean Session off and a fixed client ID) lets the broker queue messages while n8n is down and deliver them on reconnect. That only works on a broker that keeps sessions — the shared test endpoint broker.connectmq.com does not store offline sessions, so try this against your own private broker instance.
  • Retained messages are delivered immediately when the trigger subscribes, so an activated workflow may fire once for every retained topic it matches. That is often what you want for state topics and a surprise for alert topics; see retained messages.

If you run n8n in queue mode with several workers, triggers still live on the main instance. Do not start multiple main instances with the same active MQTT workflow, or each message is processed several times.

Troubleshooting checklist

SymptomLikely causeFix
Credential test fails with "Not authorized"Wrong username/password or the user lacks CONNECT rightsCheck the login with mosquitto_pub/mosquitto_sub first
Trigger connects but never firesTopic filter does not match, or ACL denies subscribePublish to the exact topic from the online client; check ACLs
Expressions return undefinedJSON Parse Body is off, payload is a stringEnable the option or parse in a Code node
Workflow fires twice per messageTwo active workflows or two n8n instances subscribeDeactivate duplicates; use one main instance
n8n Cloud cannot connectBroker only reachable on your LANUse a broker with a public endpoint and TLS

Watch your n8n topics in the browser

n8n turns MQTT messages into workflows without writing a service: one trigger, a few nodes and an MQTT publish cover most alerting and command use cases. Test each workflow with a second client before activating it, give n8n its own restricted broker user, and keep high-frequency telemetry out of workflows so execution counts stay sane.

Frequently asked questions

Does n8n have a built-in MQTT node?

Yes. n8n ships two core nodes: the MQTT Trigger, which subscribes to one or more topics and starts a workflow for every message, and the MQTT node, which publishes a message from inside a workflow. Both share the same MQTT credential.

Why does my n8n MQTT Trigger only fire while I am testing?

In the editor, 'listen for test event' only runs while the editor is open. For permanent processing the workflow must be activated (published). Only an active workflow keeps its MQTT subscription open in the background.

Can n8n parse JSON MQTT payloads automatically?

Yes. Enable the 'JSON Parse Body' option on the MQTT Trigger and the message field becomes an object, so expressions like {{ $json.message.temperature }} work. Without it the payload arrives as a string.