← All articles
AUTOMATION MQTT for IoT and Home Automation in Your Homelab 2026-02-14 · 9 min read · mqtt · iot · home-automation

MQTT for IoT and Home Automation in Your Homelab

automation 2026-02-14 · 9 min read mqtt iot home-automation mosquitto

If you're running Home Assistant, ESPHome devices, or any IoT sensors in your homelab, you need MQTT. It's the protocol that ties everything together — a lightweight publish-subscribe messaging system designed for constrained devices and unreliable networks. Your temperature sensor publishes a reading, your automation system subscribes to it, and MQTT handles the delivery.

You could use Home Assistant's built-in integrations for everything, but MQTT gives you a decoupled architecture. Devices don't need to know about each other. They publish to topics, and anything that cares about that topic subscribes. Add a new sensor? It starts publishing. Add a new dashboard? It subscribes. No reconfiguration of existing components.

MQTT publish-subscribe architecture with homelab devices

This guide sets up a production-quality MQTT broker with Eclipse Mosquitto, secures it properly, integrates it with Home Assistant, and shows practical patterns for IoT data in a homelab.

MQTT Fundamentals

If you're already familiar with MQTT, skip to the installation section. If not, here's what you need to know.

Publish-Subscribe Pattern

MQTT uses a broker (server) that sits between publishers and subscribers:

                    ┌──────────────┐
Temperature ───────▶│              │───────▶ Home Assistant
  Sensor            │  MQTT Broker │
                    │  (Mosquitto) │───────▶ Grafana Dashboard
Motion    ─────────▶│              │
  Sensor            └──────────────┘───────▶ Node-RED
                           ▲
                           │
                    Smart Plug ──────────

Topics

Topics are hierarchical, separated by /:

home/livingroom/temperature
home/livingroom/humidity
home/kitchen/motion
home/garage/door/status
homelab/server1/cpu/temp
homelab/ups/battery/percent

Wildcards:

Quality of Service (QoS)

MQTT has three QoS levels:

For homelab IoT, QoS 1 is the sweet spot. Temperature readings are fine with occasional duplicates. You don't need the overhead of QoS 2, and QoS 0 can lose data during network hiccups.

Retained Messages

A retained message stays on the broker and is immediately delivered to new subscribers. This is important for state topics — when Home Assistant restarts, it needs to know the current state of devices without waiting for the next update.

# Publish with retain flag
mosquitto_pub -t "home/garage/door/status" -m "closed" -r

Installing Mosquitto

Eclipse Mosquitto is the standard MQTT broker. It's lightweight (runs happily on a Raspberry Pi), well-maintained, and has been battle-tested for years.

Option 1: Docker/Podman Container (Recommended)

# docker-compose.yml
services:
  mosquitto:
    image: eclipse-mosquitto:2
    container_name: mosquitto
    restart: unless-stopped
    ports:
      - "1883:1883"    # MQTT
      - "9001:9001"    # WebSocket (optional)
    volumes:
      - ./mosquitto/config:/mosquitto/config
      - ./mosquitto/data:/mosquitto/data
      - ./mosquitto/log:/mosquitto/log

Option 2: Native Installation

# Ubuntu/Debian
sudo apt install mosquitto mosquitto-clients

# Fedora
sudo dnf install mosquitto

# Arch
sudo pacman -S mosquitto

Basic Configuration

Create the Mosquitto config file:

# /etc/mosquitto/mosquitto.conf (native)
# or ./mosquitto/config/mosquitto.conf (container)

# Persistence — save messages to disk
persistence true
persistence_location /mosquitto/data/

# Logging
log_dest file /mosquitto/log/mosquitto.log
log_type all

# Listener on default MQTT port
listener 1883

# IMPORTANT: Require authentication (Mosquitto 2.0+ has no anonymous by default)
allow_anonymous false
password_file /mosquitto/config/passwords.txt

Set Up Authentication

Create a password file:

# Native installation
sudo mosquitto_passwd -c /etc/mosquitto/passwords.txt homeassistant
# Enter password when prompted

# Add more users
sudo mosquitto_passwd /etc/mosquitto/passwords.txt sensor-user
sudo mosquitto_passwd /etc/mosquitto/passwords.txt grafana-reader

# For Docker, use the container:
docker exec -it mosquitto mosquitto_passwd -c /mosquitto/config/passwords.txt homeassistant

Restart Mosquitto:

sudo systemctl restart mosquitto
# or
docker compose restart mosquitto

Test the Setup

Open two terminal windows:

# Terminal 1: Subscribe
mosquitto_sub -h localhost -u homeassistant -P yourpassword -t "test/#" -v

# Terminal 2: Publish
mosquitto_pub -h localhost -u homeassistant -P yourpassword -t "test/hello" -m "it works"

You should see test/hello it works appear in Terminal 1.

Securing MQTT with TLS

Running MQTT without encryption means passwords and sensor data fly across your network in plaintext. For a homelab on a trusted network, this might be acceptable. But if any IoT devices are on a separate VLAN (they should be), or if you're exposing MQTT externally, you need TLS.

Generate Certificates

Using Let's Encrypt (if you have a domain) or self-signed certificates:

# Self-signed CA and server certificate
# Generate CA
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -subj "/CN=Homelab MQTT CA"

# Generate server key and certificate
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=mqtt.homelab.local"
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650

Configure Mosquitto for TLS

# /etc/mosquitto/mosquitto.conf

# Unencrypted listener (local only, for devices that can't do TLS)
listener 1883 127.0.0.1
allow_anonymous false
password_file /mosquitto/config/passwords.txt

# TLS listener (for network access)
listener 8883
cafile /mosquitto/certs/ca.crt
certfile /mosquitto/certs/server.crt
keyfile /mosquitto/certs/server.key
allow_anonymous false
password_file /mosquitto/config/passwords.txt

Test TLS Connection

mosquitto_sub -h mqtt.homelab.local -p 8883 \
  --cafile ca.crt \
  -u homeassistant -P yourpassword \
  -t "test/#" -v

Access Control Lists (ACLs)

Different users should have different permissions. Your temperature sensor shouldn't be able to subscribe to your door lock commands:

# /mosquitto/config/acl.conf

# Home Assistant gets full access
user homeassistant
topic readwrite #

# Sensor user can only publish to sensor topics
user sensor-user
topic write home/+/temperature
topic write home/+/humidity
topic write home/+/motion

# Grafana can only read
user grafana-reader
topic read #

# ESPHome devices
user esphome
topic readwrite homeassistant/#
topic readwrite esphome/#

Add to mosquitto.conf:

acl_file /mosquitto/config/acl.conf

Home Assistant Integration

Installing the MQTT Integration

In Home Assistant, go to Settings > Devices & Services > Add Integration > MQTT.

Configure:

MQTT Discovery

Home Assistant supports MQTT auto-discovery. Devices that follow the discovery protocol automatically appear in HA without manual configuration. ESPHome, Zigbee2MQTT, and Tasmota all support this.

The discovery prefix is homeassistant/ by default. A device publishes its configuration to:

homeassistant/sensor/livingroom_temp/config

With a payload like:

{
  "name": "Living Room Temperature",
  "state_topic": "home/livingroom/temperature",
  "unit_of_measurement": "°C",
  "device_class": "temperature",
  "unique_id": "livingroom_temp_001",
  "device": {
    "identifiers": ["esp32_livingroom"],
    "name": "Living Room Sensor",
    "manufacturer": "DIY",
    "model": "ESP32 DHT22"
  }
}

Home Assistant automatically creates a sensor entity from this configuration. When the device publishes temperature readings to home/livingroom/temperature, HA picks them up.

Manual MQTT Entities

For devices that don't support discovery, define them in configuration.yaml:

mqtt:
  sensor:
    - name: "Server Room Temperature"
      state_topic: "homelab/serverroom/temperature"
      unit_of_measurement: "°C"
      device_class: temperature

    - name: "UPS Battery"
      state_topic: "homelab/ups/battery/percent"
      unit_of_measurement: "%"
      device_class: battery

  binary_sensor:
    - name: "Garage Door"
      state_topic: "home/garage/door/status"
      payload_on: "open"
      payload_off: "closed"
      device_class: garage_door

  switch:
    - name: "Server Room Fan"
      command_topic: "homelab/serverroom/fan/set"
      state_topic: "homelab/serverroom/fan/state"
      payload_on: "ON"
      payload_off: "OFF"

ESPHome: The Best MQTT Companion

ESPHome is the easiest way to build MQTT-connected sensors. Flash an ESP32 or ESP8266 with a YAML config and it publishes sensor data over MQTT automatically.

Example: Temperature and Humidity Sensor

# esphome/livingroom-sensor.yaml
esphome:
  name: livingroom-sensor

esp32:
  board: esp32dev

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

mqtt:
  broker: 192.168.1.100
  username: esphome
  password: !secret mqtt_password
  topic_prefix: home/livingroom

sensor:
  - platform: dht
    pin: GPIO4
    model: DHT22
    temperature:
      name: "Living Room Temperature"
      filters:
        - offset: -0.5  # Calibration offset
    humidity:
      name: "Living Room Humidity"
    update_interval: 60s

  - platform: wifi_signal
    name: "Living Room Sensor WiFi"
    update_interval: 300s

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO5
      mode: INPUT_PULLUP
    name: "Living Room Motion"
    device_class: motion

Flash it with esphome run livingroom-sensor.yaml and it starts publishing to your Mosquitto broker immediately.

Homelab Monitoring Over MQTT

MQTT isn't just for IoT devices. You can publish server metrics to MQTT and consume them in Home Assistant or Grafana.

Publishing Server Metrics

A simple script that publishes system stats:

#!/bin/bash
# /usr/local/bin/mqtt-stats.sh

BROKER="192.168.1.100"
USER="sensor-user"
PASS="yourpassword"
PREFIX="homelab/$(hostname)"

# CPU temperature
CPU_TEMP=$(cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null)
if [ -n "$CPU_TEMP" ]; then
    CPU_TEMP=$((CPU_TEMP / 1000))
    mosquitto_pub -h "$BROKER" -u "$USER" -P "$PASS" -t "$PREFIX/cpu/temp" -m "$CPU_TEMP" -r
fi

# CPU usage
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print 100 - $8}')
mosquitto_pub -h "$BROKER" -u "$USER" -P "$PASS" -t "$PREFIX/cpu/usage" -m "$CPU_USAGE" -r

# Memory usage
MEM_USED=$(free -m | awk 'NR==2{printf "%.1f", $3*100/$2}')
mosquitto_pub -h "$BROKER" -u "$USER" -P "$PASS" -t "$PREFIX/memory/percent" -m "$MEM_USED" -r

# Disk usage
DISK_USED=$(df -h / | awk 'NR==2{print $5}' | tr -d '%')
mosquitto_pub -h "$BROKER" -u "$USER" -P "$PASS" -t "$PREFIX/disk/percent" -m "$DISK_USED" -r

# UPS battery (if apcupsd is running)
if command -v apcaccess &> /dev/null; then
    BATT=$(apcaccess | grep BCHARGE | awk '{print $3}')
    mosquitto_pub -h "$BROKER" -u "$USER" -P "$PASS" -t "$PREFIX/ups/battery" -m "$BATT" -r
fi

Run it every minute:

# /etc/systemd/system/mqtt-stats.timer
[Unit]
Description=Publish system stats to MQTT

[Timer]
OnBootSec=30
OnUnitActiveSec=60

[Install]
WantedBy=timers.target

Grafana + MQTT

Grafana can consume MQTT data through several paths:

  1. MQTT > InfluxDB > Grafana: Use Telegraf with the MQTT consumer plugin to write to InfluxDB. Grafana reads from InfluxDB. This is the most mature approach.
  2. MQTT > Prometheus > Grafana: Use mqtt2prometheus exporter to convert MQTT messages to Prometheus metrics.
  3. Grafana MQTT plugin: Direct MQTT connection from Grafana (community plugin, less mature).

The Telegraf approach:

# telegraf.conf
[[inputs.mqtt_consumer]]
  servers = ["tcp://192.168.1.100:1883"]
  username = "grafana-reader"
  password = "yourpassword"
  topics = [
    "homelab/#",
    "home/#"
  ]
  data_format = "value"
  data_type = "float"

[[outputs.influxdb_v2]]
  urls = ["http://localhost:8086"]
  token = "your-influxdb-token"
  organization = "homelab"
  bucket = "mqtt_data"

Zigbee2MQTT: Bridging Zigbee Devices

If you have Zigbee devices (Aqara sensors, IKEA bulbs, Sonoff switches), Zigbee2MQTT bridges them to your MQTT broker. Each Zigbee device gets its own MQTT topic:

zigbee2mqtt/living_room_sensor → {"temperature": 22.5, "humidity": 45, "battery": 98}
zigbee2mqtt/kitchen_motion → {"occupancy": true, "illuminance": 150}

Zigbee2MQTT bridging Zigbee devices to MQTT broker

Setup is straightforward:

# docker-compose.yml addition
  zigbee2mqtt:
    image: koenkk/zigbee2mqtt
    container_name: zigbee2mqtt
    restart: unless-stopped
    volumes:
      - ./zigbee2mqtt/data:/app/data
    ports:
      - "8081:8080"
    devices:
      - /dev/ttyUSB0:/dev/ttyACM0   # Your Zigbee coordinator
    environment:
      - TZ=America/Los_Angeles
# zigbee2mqtt/data/configuration.yaml
mqtt:
  base_topic: zigbee2mqtt
  server: mqtt://192.168.1.100:1883
  user: esphome
  password: yourpassword

serial:
  port: /dev/ttyACM0

frontend:
  port: 8080

advanced:
  homeassistant_discovery_topic: homeassistant
  homeassistant_status_topic: homeassistant/status

MQTT Topic Design Best Practices

Good topic design makes your system easier to manage as it grows:

Use a Consistent Hierarchy

# Location-based (recommended for home automation)
{area}/{room}/{device}/{measurement}
home/livingroom/sensor1/temperature
home/kitchen/motion1/occupancy

# Function-based (good for homelab infrastructure)
{system}/{host}/{subsystem}/{metric}
homelab/server1/cpu/temperature
homelab/nas/disk/usage

Conventions

Status Topics

Use status or availability topics for device health:

home/livingroom/sensor1/status → "online" or "offline"

Configure your devices to publish offline as their MQTT Last Will and Testament (LWT). The broker automatically publishes this when the device disconnects unexpectedly:

# ESPHome LWT config
mqtt:
  birth_message:
    topic: home/livingroom/sensor1/status
    payload: online
  will_message:
    topic: home/livingroom/sensor1/status
    payload: offline

Monitoring Mosquitto

Built-in System Topics

Mosquitto publishes statistics to $SYS/ topics:

# Subscribe to all system stats
mosquitto_sub -h localhost -u admin -P pass -t '$SYS/#' -v

Key metrics:

Prometheus Exporter

For Grafana dashboards, use the Mosquitto Prometheus exporter:

# docker-compose.yml
  mqtt-exporter:
    image: sapcc/mosquitto-exporter
    container_name: mqtt-exporter
    restart: unless-stopped
    ports:
      - "9234:9234"
    environment:
      - BROKER_ENDPOINT=tcp://mosquitto:1883
      - MQTT_USER=grafana-reader
      - MQTT_PASS=yourpassword

Troubleshooting

Messages Not Arriving

# Check if broker is receiving messages
mosquitto_sub -h localhost -u admin -P pass -t '#' -v

If you see messages here but not in your subscriber, the issue is the subscriber's topic filter or ACL permissions.

Connection Refused

# Check Mosquitto is running
systemctl status mosquitto

# Check the log
tail -f /var/log/mosquitto/mosquitto.log

# Common: password file permissions
ls -la /etc/mosquitto/passwords.txt
# Should be readable by the mosquitto user

High Latency

MQTT is designed for millisecond-level latency. If you're seeing delays:

Persistent Sessions

If a subscriber disconnects and misses messages, use persistent sessions:

mosquitto_sub -h localhost -u user -P pass -t "home/#" -i "my-client-id" -c

The -i flag sets a client ID and -c disables clean session. The broker queues messages while the client is offline and delivers them when it reconnects. This is essential for automation systems that restart occasionally.

Wrapping Up

MQTT is the glue layer for a connected homelab. Once you have Mosquitto running, every new device or service you add just publishes to or subscribes from topics. No point-to-point integrations, no API compatibility concerns, no tight coupling.

Start with Mosquitto and a few ESPHome sensors. Get comfortable with the topic hierarchy and publish-subscribe pattern. Then connect Home Assistant, add Zigbee2MQTT for your Zigbee devices, and start publishing server metrics. Before long, your entire homelab is observable and automatable through a single message bus.

The protocol is simple, the tooling is mature, and the pattern scales from 5 devices to 500 without changing architecture. For a homelab in 2026, MQTT is infrastructure you'll use for everything.