
Monitor WireGuard PiVPN Stats in Home Assistant Using MQTT
Learn how to monitor your WireGuard VPN in Home Assistant using MQTT. This step-by-step Raspberry Pi guide shows how to publish WireGuard stats to Home Assitant Dashboard
I use WireGuard as my VPN to securely access my Home Assistant dashboard and other devices on my home network when I’m away. It’s lightweight, fast, and incredibly easy to set up - which makes it perfect for small setups like a Raspberry Pi.
But once you start using WireGuard regularly, it’s nice to know a bit more about what’s happening behind the scenes.
- Which clients are connected right now?
- How much data are they transferring?
- When was the last time they connected?

Instead of running commands manually on the server, we can make this data visible directly inside Home Assistant, where it becomes part of your existing smart home dashboards, automations, and alerts.
To do that, we’ll use MQTT as the bridge between WireGuard and Home Assistant. Here’s the high-level idea:
WireGuard (on Raspberry Pi) → publishes stats via MQTT → received and visualized in Home Assistant
This setup gives you real-time VPN insights, all neatly displayed next to your other Home Assistant data - no need to SSH into your Pi or run wg show ever again.
Prerequisites #
Before we dive into the setup, let’s make sure a few things are in place. This project assumes you already have both Home Assistant and WireGuard up and running.
- Home Assistant with MQTT - You’ll need a working Home Assistant setup with MQTT integration enabled. The easiest way to do this is by installing the Mosquitto broker add-on directly from the Home Assistant Add-on Store.
Related Post: Install Mosquitto MQTT Broker
We’ll use this MQTT broker to pass WireGuard stats from our Raspberry Pi to Home Assistant, where they’ll appear as sensors on your dashboard.
- WireGuard VPN - You should already have WireGuard installed and configured on your network. In this example, I’m running it on a separate Raspberry Pi 3, which handles my VPN connections whenever I’m away from home.
Tested Setup #
Here’s what my environment looks like:
- Home Assistant OS (running on a Raspberry Pi 4)
- MQTT Broker: Home Assistant Mosquitto add-on
- WireGuard Server: Raspberry Pi 3
- Clients: iPhone, MacBook, Gl.iNet router
Creating an MQTT User in Home Assistant #
Before our Raspberry Pi can send WireGuard stats to Home Assistant, it needs a way to log in to the MQTT broker (the Mosquitto add-on in Home Assistant).
To do this safely, we’ll create a dedicated, non-admin MQTT user.
🧠 Why use a dedicated user? #
It might be tempting to reuse your main Home Assistant login - but that’s not safe or practical. A separate MQTT user keeps things secure, organized, and future-proof:
- Security: limits access - even if credentials leak, they can’t control your HA.
- Clarity: all WireGuard messages come from one clean source.
- Scalability: you can add more devices later without reusing your main account.
A simple step that makes your setup safer and easier to manage.
Steps (Home Assistant Dashboard) #
- Go to Settings → People
- Click ➕ Add Person
- Select - Allow login: ✅
- Fill in:
- Display Name: MQTT
- Username: mqtt
- Password: (choose a strong one)
- Local access only: ❌
- Administrator: ❌ (this is key - keep it a regular user)
- Click Create

Save the credentials for later. We will need it soon.
Install Mosquitto Clients on the WireGuard Host #
To send WireGuard stats to Home Assistant, your Raspberry Pi needs a way to publish messages over MQTT. That’s exactly what the Mosquitto client utilities do.
The mosquitto_pub command lets your script send data (like RX/TX bytes and last handshake times) to topics on your Home Assistant MQTT broker.
Step-by-Step Installation #
Run the following commands on your WireGuard host (in this example, a Raspberry Pi):
1. Update package lists #
sudo apt update
2. Install Mosquitto client utilities #
sudo apt install mosquitto-clients
That’s it - this installs tools like:
mosquitto_pub→ used to publish messagesmosquitto_sub→ used to subscribe and test topics
We will use mosquitto_pub in the next step to push WireGuard stats to your MQTT broker running in Home Assistant.
💡 Tip: you can test your MQTT connection right away!
- In Home Assitant's Dashboard, go to Settings → Integrations → MQTT → Configure
- In Listen to a topic section, Topic to subscribe to field, enter "test/topic"
- Click Start Listening
- In the Wireguard Host's terminal, enter:
mosquitto_pub -h homeassistant.local -t "test/topic" -m "hello" -u mqtt -P your_passwordYou should see the "hello" message coming in the Home Assistant Dashboard:

Publishing WireGuard Stats to MQTT #
Now that the Mosquitto client is installed, we can make our Raspberry Pi automatically publish WireGuard statistics to Home Assistant using MQTT.
How it Works #
WireGuard includes a built-in command that outputs live connection stats in a simple, machine-readable format:
wg show all dump
This command prints details for every peer, including:
- Public key
- Interface name
- Last handshake time
- Bytes sent (TX) and received (RX)
We’ll parse that data and publish it to MQTT topics like:
vpn/rpi3/iphone/rx
vpn/rpi3/iphone/tx
vpn/rpi3/iphone/last_handshake
Each topic corresponds to one metric per device - which Home Assistant will later subscribe to and display.
Setup on Your Wireguard Host #
- Create a folder for the script:
mkdir -p /home/rpi/hass
cd /home/rpi/hass- Create the script file:
nano publish-stats.sh- Paste in the script below (with placeholders):
#!/bin/bash
# publish-stats.sh
# Publishes WireGuard interface stats to Home Assistant via MQTT
# Run wg show in dump mode
wg show all dump | awk -F'\t' '{if(NR>1) print $1","$2","$6","$7","$8}' | \
while IFS=, read -r iface peer last_handshake tx rx; do
# Default name = first 6 chars of peer key (safe fallback)
name=${peer:0:6}
# Map specific peers to friendly names (replace these with your own)
case "$peer" in
"Szvh4KdYPvGI2slXoA82VkljYSJAGG2f3123QDDveUI=") name="iphone" ;;
"sgRd+6WR1DpR7pcsZCK5y7jsD2O2sjQF4Eh5p9PT7CY=") name="macbook" ;;
"tkGJoCzHpQcq3crkNFtxhq/eejRvh9Ny7I0XjAsn42g=") name="glinet" ;;
esac
# Publish to MQTT broker (replace with your actual credentials)
mosquitto_pub -h "homeassistant.local" -t "vpn/rpi3/$name/rx" -m "$rx" -u "mqtt_user" -P "YOUR_MQTT_PASSWORD"
mosquitto_pub -h "homeassistant.local" -t "vpn/rpi3/$name/tx" -m "$tx" -u "mqtt_user" -P "YOUR_MQTT_PASSWORD"
mosquitto_pub -h "homeassistant.local" -t "vpn/rpi3/$name/last_handshake" -m "$last_handshake" -u "mqtt_user" -P "YOUR_MQTT_PASSWORD"
done- Make it executable:
chmod +x publish-stats.shHow the Script Works #
wg show all dump- dumps all WireGuard interfaces in a tab-separated format.awk -F'\t'- extracts only the needed columns: interface, peer key, handshake time, TX, RX.Friendly names – the case section maps each peer’s public key to a readable device name.
MQTT publishing - three mosquitto_pub commands send each metric to a unique topic.
Each run of the script sends fresh stats for all connected peers to Home Assistant, ready to be displayed on your dashboard.
Automate with Cron #
You can schedule this script to run automatically - for example, every 5 minutes:
crontab -eAdd this line:
*/5 * * * * /home/rpi/hass/publish-stats.sh
This ensures your Home Assistant dashboard stays up-to-date with the latest WireGuard connection info.
💡 Tip: Test it manually first with:
/home/rpi/hass/publish-stats.shThen check Home Assistant’s MQTT > Listen to a topic for messages under vpn/rpi3/#.
Receiving WireGuard Stats in Home Assistant #
Now that our Raspberry Pi is publishing WireGuard stats to MQTT, it’s time to make Home Assistant listen to those topics and display them as sensors.
We’ll create MQTT sensors for each device (iPhone, MacBook, Gl.iNet) that show RX, TX, and Last Handshake values.
Step-by-Step Setup #
We’ll use the File Editor add-on for this part.

- Edit your Home Assistant configuration
Open configuration.yaml and add this line at the bottom:
mqtt: !include mqtt.yamlThis tells Home Assistant to load our MQTT sensors from a separate file (which keeps things clean).
- Create a new file
In the same directory, create a file called mqtt.yaml.
- Paste in the configuration below
sensor:
# === iPhone ===
- unique_id: vpn_rpi3_iphone_rx
name: "RPi3 iPhone VPN RX"
state_topic: "vpn/rpi3/iphone/rx"
value_template: >
{% set value_in_bytes = value | float %}
{% if value_in_bytes < 1024 %}
{{ value_in_bytes | round(2) }} b
{% elif value_in_bytes < 1048576 %}
{{ (value_in_bytes / 1024) | round(2) }} KB
{% elif value_in_bytes < 1073741824 %}
{{ (value_in_bytes / 1048576) | round(2) }} MB
{% else %}
{{ (value_in_bytes / 1073741824) | round(2) }} GB
{% endif %}
- unique_id: vpn_rpi3_iphone_tx
name: "RPi3 iPhone VPN TX"
state_topic: "vpn/rpi3/iphone/tx"
value_template: >
{% set value_in_bytes = value | float %}
{% if value_in_bytes < 1024 %}
{{ value_in_bytes | round(2) }} b
{% elif value_in_bytes < 1048576 %}
{{ (value_in_bytes / 1024) | round(2) }} KB
{% elif value_in_bytes < 1073741824 %}
{{ (value_in_bytes / 1048576) | round(2) }} MB
{% else %}
{{ (value_in_bytes / 1073741824) | round(2) }} GB
{% endif %}
- unique_id: vpn_rpi3_iphone_last_handshake
name: "RPi3 iPhone VPN Last Handshake"
state_topic: "vpn/rpi3/iphone/last_handshake"
value_template: >
{% set timestamp = value | int %}
{% if timestamp == 0 %}
N/A
{% else %}
{% set last_handshake = timestamp | timestamp_custom('%Y-%m-%dT%H:%M:%S', true) %}
{{ (last_handshake | as_datetime | relative_time) + ' ago' }}
{% endif %}
# === MacBook ===
- unique_id: vpn_rpi3_macbook_rx
name: "RPi3 MacBook VPN RX"
state_topic: "vpn/rpi3/macbook/rx"
value_template: >
{% set value_in_bytes = value | float %}
{% if value_in_bytes < 1024 %}
{{ value_in_bytes | round(2) }} b
{% elif value_in_bytes < 1048576 %}
{{ (value_in_bytes / 1024) | round(2) }} KB
{% elif value_in_bytes < 1073741824 %}
{{ (value_in_bytes / 1048576) | round(2) }} MB
{% else %}
{{ (value_in_bytes / 1073741824) | round(2) }} GB
{% endif %}
- unique_id: vpn_rpi3_macbook_tx
name: "RPi3 MacBook VPN TX"
state_topic: "vpn/rpi3/macbook/tx"
value_template: >
{% set value_in_bytes = value | float %}
{% if value_in_bytes < 1024 %}
{{ value_in_bytes | round(2) }} b
{% elif value_in_bytes < 1048576 %}
{{ (value_in_bytes / 1024) | round(2) }} KB
{% elif value_in_bytes < 1073741824 %}
{{ (value_in_bytes / 1048576) | round(2) }} MB
{% else %}
{{ (value_in_bytes / 1073741824) | round(2) }} GB
{% endif %}
- unique_id: vpn_rpi3_macbook_last_handshake
name: "RPi3 MacBook VPN Last Handshake"
state_topic: "vpn/rpi3/macbook/last_handshake"
value_template: >
{% set timestamp = value | int %}
{% if timestamp == 0 %}
N/A
{% else %}
{% set last_handshake = timestamp | timestamp_custom('%Y-%m-%dT%H:%M:%S', true) %}
{{ (last_handshake | as_datetime | relative_time) + ' ago' }}
{% endif %}
# === Gl.iNet Router ===
- unique_id: vpn_rpi3_glinet_rx
name: "RPi3 Gl.iNet VPN RX"
state_topic: "vpn/rpi3/glinet/rx"
value_template: >
{% set value_in_bytes = value | float %}
{% if value_in_bytes < 1024 %}
{{ value_in_bytes | round(2) }} b
{% elif value_in_bytes < 1048576 %}
{{ (value_in_bytes / 1024) | round(2) }} KB
{% elif value_in_bytes < 1073741824 %}
{{ (value_in_bytes / 1048576) | round(2) }} MB
{% else %}
{{ (value_in_bytes / 1073741824) | round(2) }} GB
{% endif %}
- unique_id: vpn_rpi3_glinet_tx
name: "RPi3 Gl.iNet VPN TX"
state_topic: "vpn/rpi3/glinet/tx"
value_template: >
{% set value_in_bytes = value | float %}
{% if value_in_bytes < 1024 %}
{{ value_in_bytes | round(2) }} b
{% elif value_in_bytes < 1048576 %}
{{ (value_in_bytes / 1024) | round(2) }} KB
{% elif value_in_bytes < 1073741824 %}
{{ (value_in_bytes / 1048576) | round(2) }} MB
{% else %}
{{ (value_in_bytes / 1073741824) | round(2) }} GB
{% endif %}
- unique_id: vpn_rpi3_glinet_last_handshake
name: "RPi3 Gl.iNet VPN Last Handshake"
state_topic: "vpn/rpi3/glinet/last_handshake"
value_template: >
{% set timestamp = value | int %}
{% if timestamp == 0 %}
N/A
{% else %}
{% set last_handshake = timestamp | timestamp_custom('%Y-%m-%dT%H:%M:%S', true) %}
{{ (last_handshake | as_datetime | relative_time) + ' ago' }}
{% endif %}- Restart Home Assistant
Once you’ve saved everything, restart Home Assistant (or reload the MQTT integration).
How It Works #
Byte conversion: The value_template automatically converts raw byte counts into KB, MB, or GB, depending on size. This keeps your dashboard clean and human-readable.
Timestamp conversion: WireGuard reports timestamps as UNIX epoch numbers. The template converts them into human-readable “x minutes ago” values - perfect for quick monitoring.
After restarting, you’ll find new MQTT sensor entities in Developer Tools → States, such as:
sensor.rpi3_iphone_vpn_rxsensor.rpi3_macbook_vpn_last_handshakesensor.rpi3_glinet_vpn_tx
Creating the Home Assistant Dashboard #
Once your MQTT sensors are working, it’s time to visualize them in Home Assistant.
We’ll create a simple but powerful dashboard that shows all your WireGuard clients - with their data usage and last handshake time - at a glance.
Create New Dashboard #
- In Home Assistant, go to Settings → Dashboards
- Click ➕ Add Dashboard
- Select New Dashboard from Scratch
- Set the Name: Network
- Click Create
Edit Dashboard #
- Open your newly created Network dashboard
- Click Edit Dashboard (top right)
- Add a new section
- Choose Grid layout
- Add any card temporarily (we’ll replace it)
- Click Show Code Editor
- Replace everything with the following YAML:
square: true
type: grid
cards:
# === iPhone ===
- show_name: true
show_icon: false
show_state: true
type: glance
title: iPhone
columns: 1
entities:
- entity: sensor.rpi3_iphone_vpn_rx
name: Received
- entity: sensor.rpi3_iphone_vpn_tx
name: Sent
- entity: sensor.rpi3_iphone_vpn_last_handshake
name: Last Handshake
# === MacBook ===
- show_name: true
show_icon: false
show_state: true
type: glance
title: MacBook
columns: 1
entities:
- entity: sensor.rpi3_macbook_vpn_rx
name: Received
- entity: sensor.rpi3_macbook_vpn_tx
name: Sent
- entity: sensor.rpi3_macbook_vpn_last_handshake
name: Last Handshake
# === Gl.iNet Router ===
- show_name: true
show_icon: false
show_state: true
type: glance
title: Gl.iNet
columns: 1
entities:
- entity: sensor.rpi3_glinet_vpn_rx
name: Received
- entity: sensor.rpi3_glinet_vpn_tx
name: Sent
- entity: sensor.rpi3_glinet_vpn_last_handshake
name: Last Handshake
grid_options:
rows: 4Dashboard Preview #
This layout displays three glance cards - one for each WireGuard client - showing real-time stats directly from your VPN server.
You can now:
- Instantly see which devices are active
- Track data usage
- Monitor last handshake times

Conclusion #
With just a small script and a few MQTT sensors, you now have real-time WireGuard monitoring inside Home Assistant.
You can see which devices are connected, how much data they’ve used, and when they last connected - all without touching the command line.
This setup is simple, lightweight, and easy to customize. You can build automations like:
- Sending a notification if a device hasn’t connected in a while
- Logging total VPN usage over time
- Combining VPN stats with other network metrics (like ping or router data)