MQTT discovery lets a device create its own entities in Home Assistant without YAML. Zigbee2MQTT, ESPHome (when used with MQTT) and many DIY devices use it.
The topics
<discovery_prefix>/<component>/[<node_id>/]<object_id>/config discovery prefix default: homeassistant
homeassistant/status birth/will: "online" / "offline"
Example config for a temperature sensor:
mosquitto_pub -h BROKER -u USER -P PASSWORD -r \
-t homeassistant/sensor/garden_node/temperature/config \
-m '{"name":"Garden temperature","state_topic":"garden_node/temperature","unit_of_measurement":"°C","device_class":"temperature","unique_id":"garden_node_temperature","device":{"identifiers":["garden_node"],"name":"Garden node"}}'
Always set unique_id (entities can then be edited in the UI) and a device block (entities get grouped under one device).
Retained config vs birth message
Two ways to make entities survive a Home Assistant restart:
- Retained config messages (
-r): simple. But retained messages stay on the broker even after the device is gone, so removed devices keep coming back. Clear them by publishing an empty retained message to the same topic. - Re-publish on birth: the device subscribes to
homeassistant/statusand re-sends its config when it seesonline. Home Assistant's docs suggest this approach: nothing stale is left on the broker.
For state topics, retained values let Home Assistant show the last value right after a restart. Decide per topic.
Broker
Home Assistant recommends the Mosquitto broker app (on Home Assistant OS). On Container installs, run Mosquitto yourself and point the MQTT integration at it. Give each device its own user and don't allow anonymous access.
Debugging
Use Settings → Devices & services → MQTT → Configure to listen to topics, or mosquitto_sub -v -t 'homeassistant/#', to see exactly what a device publishes.