The openHAB MQTT binding turns any MQTT topic into channels you can link to items, show on dashboards and use in rules. In this tutorial you will connect openHAB to an external broker, define generic MQTT things for a sensor and a switch, parse JSON payloads, publish commands from rules, and harden the setup with TLS and credentials.
How the openHAB MQTT Binding Is Organised
openHAB models MQTT in two layers. The broker bridge (mqtt:broker) is the connection: host, port, TLS, client ID and credentials. Underneath it sit things, each of which describes one device by its topics. The most flexible thing type is the generic MQTT thing (mqtt:topic), where you declare each channel and the state and command topics it uses. Items then link to those channels exactly as they would to any other binding.
| Layer | Thing type | Holds |
|---|---|---|
| Connection | mqtt:broker (bridge) |
Host, port, TLS, client ID, username, password, last will |
| Device | mqtt:topic (generic thing) |
Channels with state and command topics |
| Device (auto) | Home Assistant or Homie things | Created from discovery messages |
| Model | Items | Linked to channels, used in UI and rules |
A single broker bridge can serve hundreds of things, and it uses only one MQTT connection. That matters on plans with connection quotas: openHAB counts as one client however many devices it models.
Install the binding from Settings > Add-on Store > Bindings > MQTT Binding. If your devices send JSON, also install the JSONPath Transformation from the transformations section.
Connecting openHAB to an MQTT Broker
You can create the bridge in the UI (Things > + > MQTT Binding > MQTT Broker) or in a .things file. Text configuration is easier to share and back up, so this tutorial uses it. Create conf/things/mqtt.things:
Bridge mqtt:broker:connectmq "ConnectMQ Broker" [
host="broker.connectmq.com",
port=1883,
secure=false,
clientID="openhab-r4t8w1",
lwtTopic="connectmq/demo/r4t8w1/openhab/status",
lwtMessage="offline",
lwtRetain=true,
birthTopic="connectmq/demo/r4t8w1/openhab/status",
birthMessage="online",
birthRetain=true
] {
Thing topic greenhouse "Greenhouse Sensor" {
Channels:
Type number : temperature "Temperature" [
stateTopic="connectmq/demo/r4t8w1/greenhouse/telemetry",
transformationPattern="JSONPATH:$.temp",
unit="°C"
]
Type number : humidity "Humidity" [
stateTopic="connectmq/demo/r4t8w1/greenhouse/telemetry",
transformationPattern="JSONPATH:$.hum",
unit="%"
]
Type switch : fan "Vent Fan" [
stateTopic="connectmq/demo/r4t8w1/greenhouse/fan/state",
commandTopic="connectmq/demo/r4t8w1/greenhouse/fan/set",
on="ON",
off="OFF"
]
Type contact : door "Door" [
stateTopic="connectmq/demo/r4t8w1/greenhouse/door",
on="OPEN",
off="CLOSED"
]
}
}
This connects to the public test broker anonymously. Replace r4t8w1 with your own random string, because the public area is shared and readable by everyone. The client ID must be non-empty and unique; reusing one that another client holds will make both connections drop repeatedly.
Check Settings > Things: the bridge should be ONLINE within a few seconds, followed by the greenhouse thing.
Linking items
Create conf/items/greenhouse.items:
Number:Temperature GH_Temperature "Temperature [%.1f °C]" <temperature> { channel="mqtt:topic:connectmq:greenhouse:temperature" }
Number:Dimensionless GH_Humidity "Humidity [%.0f %%]" <humidity> { channel="mqtt:topic:connectmq:greenhouse:humidity" }
Switch GH_Fan "Vent Fan" <fan> { channel="mqtt:topic:connectmq:greenhouse:fan" }
Contact GH_Door "Door [%s]" <door> { channel="mqtt:topic:connectmq:greenhouse:door" }
Note the channel UID pattern: mqtt:topic:<bridge id>:<thing id>:<channel id>. A typo there is the most common reason an item stays NULL.
Testing the openHAB MQTT Channels
Simulate the device from a terminal:
# sensor reading (JSON parsed by JSONPath)
mosquitto_pub -h broker.connectmq.com -p 1883 -i sim-r4t8w1 \
-t 'connectmq/demo/r4t8w1/greenhouse/telemetry' -m '{"temp":24.6,"hum":71}'
# door contact
mosquitto_pub -h broker.connectmq.com -p 1883 -i sim-r4t8w1 \
-t 'connectmq/demo/r4t8w1/greenhouse/door' -m 'OPEN'
# watch the commands openHAB sends
mosquitto_sub -h broker.connectmq.com -p 1883 -i mon-r4t8w1 \
-t 'connectmq/demo/r4t8w1/greenhouse/fan/set' -v
Toggle the fan in the openHAB UI and the ON or OFF command appears in the subscriber window. A real device would act on it and publish its new state to fan/state, which openHAB uses to update the item. Keeping command and state topics separate means the UI shows the confirmed state, not just the last click.
Parsing JSON and Formatting Commands
Most modern devices publish JSON. Besides transformationPattern for incoming values, the generic thing supports formatBeforePublish for outgoing ones. For example, a dimmer that expects {"brightness": 40}:
Type dimmer : lamp "Grow Lamp" [
stateTopic="connectmq/demo/r4t8w1/greenhouse/lamp/state",
commandTopic="connectmq/demo/r4t8w1/greenhouse/lamp/set",
transformationPattern="JSONPATH:$.brightness",
formatBeforePublish="{\"brightness\": %s}",
min=0,
max=100
]
Transformations can be chained with the ∩ character in the pattern if you need several steps, for example JSONPath followed by a MAP lookup. Keep chains short; when the logic grows, a rule is easier to debug.
Publishing MQTT Messages from openHAB Rules
Commands linked to channels cover most needs, but sometimes you want to publish to an arbitrary topic, for example to send a schedule to a controller. The broker bridge exposes a publishMQTT action for that. In a DSL rule file conf/rules/greenhouse.rules:
rule "Greenhouse overheat"
when
Item GH_Temperature changed
then
val temp = (GH_Temperature.state as QuantityType<Number>).toUnit("°C").doubleValue
if (temp > 30.0 && GH_Fan.state != ON) {
GH_Fan.sendCommand(ON)
val mqtt = getActions("mqtt", "mqtt:broker:connectmq")
mqtt.publishMQTT("connectmq/demo/r4t8w1/greenhouse/event",
"{\"event\":\"overheat\",\"temp\":" + temp + "}", false)
}
end
The same action is available from JavaScript rules through actions.get("mqtt", "mqtt:broker:connectmq"). Avoid publishing to the same topic a channel subscribes to unless you intend to create a loop.
Triggering rules from raw topics
If you only want to react to a message without modelling an item, add a trigger channel to the bridge:
Bridge mqtt:broker:connectmq "ConnectMQ Broker" [ ... ] {
Channels:
Type publishTrigger : alarms "Alarms" [
stateTopic="connectmq/demo/r4t8w1/+/alarm",
separator="#"
]
}
A rule triggered by Channel "mqtt:broker:connectmq:alarms" triggered receives the topic and payload joined by the separator, so one rule can handle alarms from every device.
Production Setup with TLS and Credentials
Before connecting real devices, move off the public test area. Create a private broker, then update the bridge:
Bridge mqtt:broker:connectmq "ConnectMQ Broker" [
host="broker.connectmq.com",
port=8883,
secure=true,
certificatepin=false,
publickeypin=false,
clientID="YOUR_CLIENT_ID",
username="YOUR_USERNAME",
password="YOUR_PASSWORD",
lwtTopic="site1/openhab/status",
lwtMessage="offline",
lwtRetain=true
]
ConnectMQ's certificate is issued by Let's Encrypt, which Java trusts by default, so no extra certificate import is needed. Certificate pinning is switched off explicitly because Let's Encrypt certificates are renewed every few months; a pinned certificate would make the bridge reject the broker after the next renewal. Use the client ID exactly as issued, since it is bound to the credentials. For more on locking down the whole system, read the MQTT security best practices.
If you prefer to run your broker locally inside openHAB's network, you can still bridge it to the cloud later, but a fully managed MQTT service removes the need to maintain a separate broker host and lets remote sites and phones reach the same topics.
Showing Device Availability
A generic thing stays ONLINE as long as the bridge is connected, even if the device behind it lost power hours ago. To make that visible, have each device publish a retained online message when it connects and set a retained offline last will. Then add availability settings to the thing:
Thing topic greenhouse "Greenhouse Sensor" [
availabilityTopic="connectmq/demo/r4t8w1/greenhouse/status",
payloadAvailable="online",
payloadNotAvailable="offline"
] {
// channels as before
}
When the device drops off, the broker publishes its will, openHAB marks the thing OFFLINE and linked items become UNDEF. Rules and dashboards can then distinguish "the sensor reads 0" from "the sensor is gone", which matters a great deal for anything that drives heating, irrigation or alarms.
Troubleshooting Checklist
- Bridge stays OFFLINE. Check host and port, and that
secure=trueis set only with port 8883. Look inopenhab.logfor the reason code. - Bridge flaps between ONLINE and OFFLINE. Duplicate client ID; another openHAB instance or test tool uses the same one.
- Thing ONLINE but item NULL. Wrong channel UID in the item, a topic typo, or the JSONPath add-on is missing. Use
log:set DEBUG org.openhab.binding.mqttin the console to see every received message. - Switch shows UNDEF. The payload does not match
onoroffexactly; values are case-sensitive. - Commands do nothing. Make sure the device listens on the command topic, and that you are not publishing to its state topic.
Where openHAB Fits in a Wider System
openHAB is one consumer on the broker, not the owner of the data. ESPHome nodes, Tasmota plugs and Zigbee2MQTT can all publish to the same broker, and other tools can read the same topics. The ESPHome MQTT tutorial shows how to publish from YAML-configured devices, and Tasmota MQTT covers flashed smart plugs. For the bigger architectural picture, see the IoT automation guide. And if you are still comparing brokers, the overview of a cloud MQTT broker explains the trade-offs.
Run openHAB on a ConnectMQ Broker
ConnectMQ provides a private MQTT 3.1.1 and 5.0 broker with TLS, generated credentials and a live topic explorer that makes debugging openHAB channels straightforward. Create a free Serverless broker at app.connectmq.com with no credit card, paste the credentials into your bridge, and your openHAB things are online.
Frequently Asked Questions
Does openHAB include its own MQTT broker?
No. Current openHAB versions only provide the client binding, so you need an external broker such as a local Mosquitto instance or a cloud broker like ConnectMQ.
Can openHAB use MQTT 5?
The broker bridge has an mqttVersion parameter that can be set to V5. Version 3.1.1 remains the default and works for nearly all devices.
How many MQTT connections does openHAB use?
One per broker bridge, regardless of how many generic things sit under it. That makes it efficient on connection-limited plans.
Why do my items update but commands are not sent?
The channel probably has no commandTopic, or the item is linked read-only. Add a command topic and confirm with a subscriber that the message is published.



