Shelly devices speak MQTT natively: open the device's web UI, enable MQTT, enter your broker's host, port and credentials, and the relay starts publishing its state and accepting commands. What differs is the topic layout. Gen1 devices (Shelly 1, 2.5, Plug S, H&T…) use a fixed shellies/... tree with plain-text commands, while Gen2, Plus, Pro and Gen3 devices use a JSON-RPC API that you can call over MQTT.
This tutorial covers both generations: the settings, the topics you will see, how to send commands, and how to verify everything from the command line before you wire it into Home Assistant, openHAB or your own code.
Which generation do you have?
| Gen1 | Gen2 / Plus / Pro / Gen3 | |
|---|---|---|
| Examples | Shelly 1, 1PM, 2.5, Plug S, Dimmer 2, H&T | Plus 1PM, Plus Plug S, Pro 4PM, 1 Mini Gen3 |
| MQTT settings | Internet & Security → Advanced – Developer Settings | Settings → MQTT (Networks → MQTT on newer UIs) |
| Default prefix | shellies/<model>-<id> | <model>-<id> (e.g. shellyplus1pm-a8032ab12345) |
| Payloads | Plain text (on, off, numbers) | JSON (status objects, RPC frames) |
| Cloud while MQTT is on | Disabled | Can stay enabled |
| TLS | Firmware-dependent | Built-in CA bundle, no validation, or your own CA |
The device ID is derived from the MAC address. You will find it in the web UI under device info, or simply subscribe to # once the device is connected and read it from the first topics that arrive.
Gen1 setup
In the Gen1 web UI open Internet & Security → Advanced – Developer Settings and tick Enable action execution via MQTT. Fill in:
- Server:
broker.connectmq.com:1883 - Username / Password: your broker credentials
- Use custom MQTT prefix (optional): for example
testmqtt/shelly/hallwayinstead ofshellies/shelly1-A1B2C3 - Clean session, Keep alive (60 s is fine), Max QoS and Retain: retain is useful so a dashboard sees the last relay state immediately
Save, and the device reboots its MQTT connection. Remember that this turns off Shelly Cloud on Gen1 devices.
Gen1 topics
shellies/shelly1pm-A1B2C3/online true | false (Last Will)
shellies/shelly1pm-A1B2C3/relay/0 on | off
shellies/shelly1pm-A1B2C3/relay/0/power instantaneous power in W
shellies/shelly1pm-A1B2C3/relay/0/energy energy counter (watt-minutes)
shellies/shelly1pm-A1B2C3/input/0 0 | 1
shellies/shelly1pm-A1B2C3/temperature internal temperature in °C
shellies/shelly1pm-A1B2C3/relay/0/command ← publish on | off | toggle
shellies/announce device announces itself (JSON)
shellies/command ← publish announce | updateCommands are plain strings. To switch the relay, publish on to .../relay/0/command; the device answers by publishing the new value on .../relay/0. Publishing announce to shellies/command makes every Gen1 device on the broker report its ID, IP and firmware — a handy discovery trick. Rollers use roller/0/command with open, close, stop, and roller/0/command/pos with a percentage.
Battery devices such as the H&T sleep most of the time: they wake up, publish sensor/temperature and sensor/humidity, and disconnect. Make the subscriber side rely on retained values, not on the device being online.
Gen2, Plus and Pro setup
Open Settings → MQTT and enable it:
- Server:
broker.connectmq.com:8883(or:1883without TLS) - Client ID: defaults to the device ID; keep it unique — see MQTT client ID best practices
- Username / Password
- SSL/TLS: No TLS, TLS no validation, TLS with default CA (use this for public certificates) or TLS with user CA
- MQTT Prefix: defaults to the device ID; set e.g.
testmqtt/shelly/plug1 - RPC status notifications over MQTT: publishes events to
<prefix>/events/rpc - Generic status update over MQTT: publishes component status to
<prefix>/status/<component> - Enable MQTT Control: accepts simple commands on
<prefix>/command/...
A reboot is required after changing MQTT settings. You can also do the whole configuration without the UI, by calling the RPC API over HTTP:
curl -s -X POST http://192.168.1.50/rpc/MQTT.SetConfig \
-d '{"config":{"enable":true,"server":"broker.connectmq.com:8883","ssl_ca":"ca.pem",
"user":"username","pass":"password","topic_prefix":"testmqtt/shelly/plug1",
"rpc_ntf":true,"status_ntf":true,"enable_control":true}}'
curl -s -X POST http://192.168.1.50/rpc/Shelly.Reboot"ssl_ca": "ca.pem" selects the built-in CA bundle; "*" disables validation and "user_ca.pem" uses a certificate you uploaded. Avoid "*" outside a lab — see testing a TLS connection.
Gen2 topics
testmqtt/shelly/plug1/online true | false (Last Will)
testmqtt/shelly/plug1/status/switch:0 {"id":0,"output":true,"apower":12.4,...}
testmqtt/shelly/plug1/events/rpc {"method":"NotifyStatus","params":{...}}
testmqtt/shelly/plug1/command ← publish status_update
testmqtt/shelly/plug1/command/switch:0 ← publish on | off | toggle
testmqtt/shelly/plug1/rpc ← publish JSON-RPC requestsComponents are addressed as type:index — switch:0, input:1, cover:0, temperature:100. With Generic status update on, each component's full status lands on its own topic, which is the easiest format to consume. events/rpc carries NotifyStatus deltas and NotifyEvent messages (button presses, for example).
RPC over MQTT
Every Gen2 method you can call over HTTP also works over MQTT. Publish a JSON-RPC frame to <prefix>/rpc; the device answers on <src>/rpc, where src is the value you put in the request. This is a classic request/response pattern.
{"id": 1, "src": "testmqtt/shelly/cli", "method": "Switch.Set", "params": {"id": 0, "on": true}}{"id": 1, "src": "shellyplusplugs-a8032ab12345", "dst": "testmqtt/shelly/cli", "result": {"was_on": false}}Useful methods: Shelly.GetStatus, Shelly.GetDeviceInfo, Switch.Toggle, Switch.GetStatus, Cover.GoToPosition, Sys.SetConfig. Errors come back with an error object (code and message) instead of result.
Here is a small Python helper (paho-mqtt 2.x) that sends an RPC call and waits for the matching response:
import json, os, threading
import paho.mqtt.client as mqtt
PREFIX = "testmqtt/shelly/plug1"
SRC = "testmqtt/shelly/cli"
done = threading.Event()
def on_connect(client, userdata, flags, reason_code, properties):
client.subscribe(f"{SRC}/rpc", qos=1)
def on_subscribe(client, userdata, mid, reason_codes, properties):
req = {"id": 1, "src": SRC, "method": "Shelly.GetStatus"}
client.publish(f"{PREFIX}/rpc", json.dumps(req), qos=1)
def on_message(client, userdata, msg):
resp = json.loads(msg.payload)
if resp.get("id") == 1:
print(json.dumps(resp.get("result", resp.get("error")), indent=2))
done.set()
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="shelly-rpc-cli")
client.username_pw_set(os.environ["MQTT_USER"], os.environ["MQTT_PASS"])
client.tls_set()
client.on_connect, client.on_subscribe, client.on_message = on_connect, on_subscribe, on_message
client.connect("broker.connectmq.com", 8883)
client.loop_start()
print("ok" if done.wait(10) else "no response (check prefix and RPC setting)")
client.loop_stop()Test the setup
Before adding the device to any home-automation software, watch its traffic directly:
mosquitto_sub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
-u "$MQTT_USER" -P "$MQTT_PASS" -t 'shellies/#' -t 'testmqtt/shelly/#' -vThen toggle the relay from a second terminal and check that the state topic follows:
# Gen1
mosquitto_pub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
-u "$MQTT_USER" -P "$MQTT_PASS" -t 'shellies/shelly1pm-A1B2C3/relay/0/command' -m toggle
# Gen2 with "Enable MQTT Control"
mosquitto_pub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
-u "$MQTT_USER" -P "$MQTT_PASS" -t 'testmqtt/shelly/plug1/command/switch:0' -m toggleYou can do the same in the browser with the online MQTT client: subscribe to the prefix with #, publish status_update to <prefix>/command and the device responds with its full status. If you are unsure whether a wildcard covers the topics you expect, paste them into the topic matcher.
Watch your Shelly topics in the browser
If nothing appears: check that the online topic ever turns true, that the port matches the TLS setting (8883 with TLS, 1883 without), and that the device can resolve the broker's hostname. A device that keeps reconnecting is often fighting another client with the same client ID.
Integration notes
- Home Assistant: Shelly devices are usually added with the native Shelly integration, which does not use MQTT. If you prefer MQTT, define entities manually or use a discovery script; see Home Assistant and MQTT.
- Topic design: a custom prefix such as
home/<room>/<device>keeps Shelly, Tasmota and Zigbee devices in one consistent tree — see smart home topic design. - Retained state: enable retain (Gen1) or rely on
status/...plus astatus_updaterequest at startup (Gen2) so dashboards do not show "unknown" after a restart. - Mixing generations: write your consumers against both layouts, or normalize them in Node-RED before they reach your application.
Shelly's MQTT support is one of the most complete in consumer hardware: plain topics on Gen1, a full RPC API on Gen2 and later. Configure a custom prefix, watch the traffic with a subscriber before integrating, and lock each device down to its own topics.
Frequently asked questions
Does enabling MQTT disable the Shelly Cloud?
On Gen1 devices, yes: turning on MQTT switches off Shelly Cloud. On Gen2, Plus, Pro and Gen3 devices MQTT and the cloud connection can run at the same time.
What is the default MQTT topic of a Shelly device?
Gen1 devices use shellies/<model>-<deviceid>/..., for example shellies/shelly1-A1B2C3/relay/0. Gen2 and later use the device ID as the topic prefix, for example shellyplus1pm-a8032ab12345/status/switch:0. Both can be replaced with a custom prefix.
Can Shelly devices connect to an MQTT broker over TLS?
Gen2 and later support TLS with the built-in CA bundle, without validation, or with your own CA certificate, so port 8883 works. Gen1 support depends on the firmware; plain port 1883 on a trusted network is the common setup there.



