MQTT is the messaging backbone underneath much of a working Home Assistant deployment. ESPHome devices publish their state over MQTT. Zigbee2MQTT bridges the Zigbee network to Home Assistant via MQTT. LoRaWAN network servers publish device uplinks to MQTT topics. Custom scripts and applications communicate with Home Assistant through MQTT. A serious Home Assistant deployment ends up running an MQTT broker (Mosquitto, almost always) as part of the graybox, with many of the integrations flowing through it. This page covers MQTT fundamentals, setting up Mosquitto as the broker, designing topics that scale, securing the broker with authentication, and the failure modes that affect MQTT deployments. For most agricultural operations, MQTT becomes visible only when something goes wrong with it; making it invisible by setting it up well is the goal.
MQTT fundamentals.
MQTT (Message Queuing Telemetry Transport) is a lightweight publish/subscribe messaging protocol. Three concepts.
Broker.
The central service that receives messages and routes them to interested subscribers. The broker is the only long-running piece of the MQTT infrastructure. Everything else connects to the broker as clients.
Publisher.
A client that sends messages. A temperature sensor publishes its reading; a Home Assistant automation publishes a command; a script publishes an event notification.
Subscriber.
A client that receives messages by subscribing to specific topics. Home Assistant subscribes to device topics to receive their data; a display panel subscribes to dashboard-relevant topics; an external system subscribes to relay commands out of Home Assistant.
Topics.
Strings that identify channels of communication. A topic looks like a file path — `greenhouse/zone1/temperature`, `home/kitchen/light`, `farm/irrigation/valve3/state`. Publishers send messages to topics; subscribers subscribe to topics (with wildcards optionally) to receive messages.
Quality of service (QoS).
Three delivery guarantees:
- QoS 0. "Fire and forget." Message sent once, no acknowledgment. Fast; may be lost. - QoS 1. "At least once." Message delivered at least once, possibly more. - QoS 2. "Exactly once." Message delivered exactly once. Most reliable, highest overhead.
For most agricultural sensor data, QoS 0 is fine — an occasional lost sensor reading is not a problem given the continuous flow. For control messages where the action needs to happen reliably, QoS 1 or 2.
Retained messages.
A publisher can mark a message as "retained," meaning the broker keeps the last such message and delivers it to any new subscriber immediately. Useful for state topics where a new subscriber needs to know the current state without waiting for the next update.
Last will and testament (LWT).
A client can configure a last-will message that the broker publishes if the client disconnects unexpectedly. Useful for availability tracking — a device's LWT publishes "offline" on disconnect, so other clients know the device is no longer reporting.
Why Home Assistant uses MQTT.
Several specific reasons MQTT appears so often in Home Assistant deployments.
Ecosystem momentum.
ESPHome, Tasmota, and many other open-source firmware projects use MQTT as their primary Home Assistant integration. Deploying any of these brings MQTT into the picture.
Zigbee2MQTT.
One of the two common Zigbee paths uses MQTT as the bridge. Operations using Zigbee2MQTT are using MQTT.
LoRaWAN.
Most LoRaWAN network server integrations with Home Assistant flow through MQTT. Same pattern for some cellular IoT platforms.
Simplicity.
MQTT is conceptually simple. The publish/subscribe model maps well to sensor/actuator scenarios. The protocol overhead is small; messages can be tiny; brokers are efficient.
Language and platform independence.
MQTT clients exist for every language and platform. A custom script in Python, Node.js, bash, C++, or anything else can publish to or subscribe from the same broker.
Decoupling.
Publishers and subscribers don't need to know about each other — they only need to agree on topics. This decoupling lets components be developed, deployed, and changed independently.
Mosquitto as the broker.
Mosquitto is by far the most common MQTT broker for Home Assistant deployments. Open source, mature, lightweight, well-maintained.
Deployment options.
Home Assistant add-on. For Home Assistant OS and Supervised installations. The Mosquitto broker add-on installs and manages Mosquitto through the Home Assistant interface. Simplest path for readers on those installations.
Docker container. For Docker-based Home Assistant installations (the graybox pattern). Mosquitto runs as a separate container alongside Home Assistant. Configuration through docker-compose.yml and a mosquitto.conf file.
Native package. Ubuntu, Debian, and other Linux distributions have Mosquitto packages available. Install with the package manager and configure through its standard configuration files.
Dedicated hardware. For large-scale deployments, Mosquitto can run on dedicated hardware separate from Home Assistant. Uncommon but useful for very large deployments.
For most agricultural operations, the graybox pattern (Docker container alongside Home Assistant) is the standard choice.
Basic Mosquitto configuration.
Password authentication.
Mosquitto 2.x requires authentication by default. Create a password file with one or more users.
```bash
# Using mosquittopasswd (available in the mosquitto-clients package) mosquittopasswd -c /path/to/passwd homeassistant
# Enter password when prompted ```
Each client (Home Assistant, ESPHome devices, etc.) uses one of these credentials to authenticate.
TLS encryption.
For deployments where MQTT traffic crosses untrusted networks (or where security is a requirement), TLS encryption protects against eavesdropping. Mosquitto supports TLS with certificates. For deployments where all traffic stays on the local network, TLS is usually unnecessary overhead.
The Home Assistant MQTT integration.
Adding the MQTT integration in Home Assistant.
Setup.
Settings → Devices & Services → Add Integration → MQTT. Enter connection details: - Broker: IP address or hostname (often `localhost` for local broker, specific IP for separate broker) - Port: 1883 (standard) or custom - Username and password from the Mosquitto password file - Optional: discovery prefix (defaults to `homeassistant`)
Home Assistant connects to the broker and begins listening for messages.
MQTT discovery.
Home Assistant supports automatic device discovery through MQTT. Devices (or services) publish device-description messages to specific topics following a convention (`homeassistant/sensor/.../config` and similar). Home Assistant reads these messages and automatically creates matching entities.
ESPHome, Tasmota, and Zigbee2MQTT all use MQTT discovery by default — devices appear in Home Assistant without manual configuration.
Manual MQTT entities.
For devices or services that don't use MQTT discovery, Home Assistant entities can be created manually through YAML configuration.
The manual approach is more work but provides complete control over topic structure and message parsing.
Topic design.
Topic structure matters for maintainability. A well-designed hierarchy makes the MQTT deployment navigable; a flat or ad-hoc structure becomes difficult at scale.
The recommended hierarchical pattern.
Match the topic hierarchy to the physical operation hierarchy. For example:
``` farm/greenhouse1/zone1/temperature farm/greenhouse1/zone1/humidity farm/greenhouse1/zone1/ventfan/command farm/greenhouse1/zone1/ventfan/state farm/greenhouse2/zone1/temperature farm/packhouse/cold_storage/temperature ```
The structure is readable, predictable, and allows wildcard subscriptions ("all temperatures under greenhouse1" or "all vent fans across the farm").
Why not use Home Assistant's default discovery topics.
Home Assistant's MQTT discovery publishes to topics like `homeassistant/sensor/greenhousezone1temp/state`. This works but the topic structure mixes Home Assistant-specific routing with the actual data hierarchy. For operations that may have other MQTT clients (dashboards, scripts, other systems) reading the same data, a separate "real" topic structure for data is cleaner, with Home Assistant discovery alongside.
Wildcards.
MQTT supports two wildcards: - `+` (single level). `farm/+/zone1/temperature` matches `farm/greenhouse1/zone1/temperature` and `farm/greenhouse2/zone1/temperature`. - `#` (multi-level, only at the end). `farm/greenhouse1/#` matches everything under greenhouse1.
Wildcards enable subscribers to efficiently receive many related messages without enumerating every topic.
Retain policy.
State topics (reporting current state) should generally be retained — a new subscriber needs the current state immediately. Event topics (reporting something that happened) should generally not be retained — events are momentary; replaying old events is usually wrong.
Payload format.
MQTT payloads are bytes; the format is by convention. Two common choices:
- Simple text. The payload is just the value — "23.5" for a temperature, "ON" for a switch state. Simple; easy to parse; limited to single values. - JSON. The payload is a JSON object with multiple fields — `{"temperature": 23.5, "humidity": 65.2, "battery": 89}`. More information per message; requires JSON parsing in subscribers.
For agricultural operations, JSON is typically preferable when devices report multiple related values. Simple text is fine for single-value topics.
MQTT for specific scenarios.
How MQTT appears in different deployment patterns.
ESPHome devices.
ESPHome's MQTT integration publishes each device's sensors and exposes switches. A temperature sensor on an ESPHome device might publish to `greenhouse/zone1/temperature/state` periodically. A relay might subscribe to `greenhouse/zone1/fan/command` for on/off commands and publish current state to `greenhouse/zone1/fan/state`.
Home Assistant discovers these via MQTT discovery and creates corresponding entities automatically.
Zigbee2MQTT.
Zigbee2MQTT publishes each Zigbee device's data to a topic based on the device name. An Aqara temperature sensor named "greenhousezone1temp1" publishes to `zigbee2mqtt/greenhousezone1temp1` with a JSON payload containing temperature, humidity, battery, and other fields. Home Assistant reads these via MQTT discovery messages that Zigbee2MQTT also publishes.
LoRaWAN network server integration.
ChirpStack, TTN, and similar network servers publish device uplink data to MQTT topics. The topics follow the network server's convention (ChirpStack: `application/{appid}/device/{deveui}/event/up`). Home Assistant MQTT sensor entities subscribe to these topics and extract data from the JSON payloads.
Custom scripts.
A Python script that reads sensor data from a source outside Home Assistant's direct integrations can publish to MQTT topics that Home Assistant subscribes to. Similarly, a custom script might subscribe to Home Assistant state changes and react programmatically. MQTT is the common meeting point.
External dashboards or reporting systems.
Grafana, InfluxDB, Node-RED, and other tools can subscribe to MQTT to receive data independently of Home Assistant. The MQTT broker serves as a data bus shared across multiple consumers.
MQTT failure modes.
Specific problems that affect MQTT deployments.
The broker that wasn't running. After a restart, the MQTT broker failed to start (configuration error, permission problem). Home Assistant reported all MQTT devices as unavailable. Fix: service monitoring on the broker, startup diagnostics in the broker's log.
The authentication that changed without all clients updating. Operator rotated the Home Assistant MQTT password in the broker but didn't update the devices that used the same password. Devices lost connectivity. Fix: coordinated credential rotation, or device-specific credentials.
The retained message that stuck. A state topic had a stale retained message that kept showing an old state to new subscribers even after the device disconnected. Fix: devices publish explicit "unavailable" LWT messages; operators periodically clear stale retained messages.
The QoS mismatch. A critical command was published with QoS 0; the subscriber missed it during a brief network blip. Fix: use QoS 1 or 2 for commands where delivery is important.
The topic naming scheme that drifted. Over time, different devices and services used different topic naming conventions. Wildcards that should have worked didn't; similar data ended up in different places. Fix: topic-naming convention documented and enforced, periodic audits.
The JSON payload that changed. A device firmware update changed JSON field names; subscribers parsing the old field names broke. Fix: version JSON payloads, test after firmware updates, maintain subscriber compatibility through transitions.
The broker that ran out of disk space. Persistent retained messages accumulated without bounds over years. The broker's disk filled. Fix: disk monitoring, retention policies for retained messages, periodic cleanup.
The client that published too fast. A buggy device published sensor data 100 times per second. The broker handled it but downstream subscribers struggled. Fix: rate limiting in well-designed devices, anomaly detection on publish frequency.
The missing LWT. A device disconnected ungracefully; its state topic retained its last-known "ON" state. Subscribers believed the device was still present for hours until reconnect or discovery eventually refreshed. Fix: devices publish LWT messages so disconnect is visible.
The cross-operation interference. Two separate operations on the same broker mixed their topics; one operation's actions affected the other. Fix: topic namespacing (prefix each operation's topics), or separate brokers.
What not to do.
Don't leave the broker unauthenticated. Mosquitto 2.x defaults to requiring authentication; don't disable it. An unauthenticated broker is wide open.
Don't use default credentials. Generic "admin/admin" or similar default credentials are not adequate authentication.
Don't assume MQTT is real-time. MQTT is fast but not guaranteed real-time. For tight-timing control, local direct integration is better than MQTT.
Don't publish high-frequency data if you don't need it. A sensor reporting every second where once per minute would suffice wastes resources.
Don't skip retained messages for state topics. New subscribers need current state; retained messages provide it. Without retention, subscribers have to wait for the next update.
Don't retain event messages. Events are momentary; retained event messages mislead new subscribers into thinking something is happening that already happened.
Don't mix critical and non-critical traffic in ways that can't be separated. For very large deployments, separate brokers or separate topic namespaces for different criticality levels prevent non-critical volume from impacting critical reliability.
Don't forget the LWT. Devices without LWT messages can appear online when they're actually offline. Properly configured LWT makes this visible.