MQTT Broker Setup on Windows 11 with Docker for IoT
Tech Setup
Reviewed July 30, 2026

Introduction
Developing and testing Internet of Things (IoT) applications locally on Windows 11 often presents friction. While Linux remains the native habitat for edge infrastructure, modern Windows development environments—bolstered by Windows Subsystem for Linux (WSL 2) and Docker Desktop—offer a robust, containerized alternative. For developers building systems that rely on lightweight publish-subscribe messaging, running an MQTT (Message Queuing Telemetry Transport) broker locally is a standard requirement.
This guide details how to spin up, configure, and secure an enterprise-grade MQTT broker—Eclipse Mosquitto—on Windows 11 using Docker. We will move beyond a basic "Hello World" deployment to establish a persistent, secure, and production-aligned local development environment suitable for Tier-1 software engineering workflows.
Prerequisites and Environment Setup
Before configuring the MQTT broker, ensure your Windows 11 environment is optimized for containerized workloads. Running Docker on Windows requires the backend integration of WSL 2 for optimal I/O performance and resource utilization.
System Requirements
- OS: Windows 11 Pro, Enterprise, or Education (Home is supported with WSL 2 backend, but Pro is recommended for Hyper-V features).
- Virtualization: Enabled in UEFI/BIOS.
- RAM: Minimum 8GB allocated to the system (Docker Desktop should be configured to use at least 2GB).
- Tools: PowerShell 7+ or Windows Terminal, Docker Desktop for Windows, and an MQTT client utility (such as
mosquitto-clientsormqttui).
Verifying Docker and WSL 2
Open your terminal (Windows Terminal is preferred) and verify that your Docker daemon is running and communicating correctly with the WSL 2 backend:
docker version
wsl --status
Ensure that the Docker Desktop context is set to default or windows-integration is active for your preferred WSL distribution.
Designing the Directory Structure
To maintain a clean separation of concerns, we will structure our local deployment using a dedicated project directory. This directory will house our docker-compose.yml file, the Mosquitto configuration file (mosquitto.conf), and persistent storage volumes for logs, data, and TLS certificates.
Open your terminal and run the following commands to initialize the workspace:
mkdir -p C:\docker\mqtt\config
mkdir -p C:\docker\mqtt\data
mkdir -p C:\docker\mqtt\log
cd C:\docker\mqtt
This layout ensures that container restarts do not wipe out retained messages, client session states, or access control lists (ACLs).
Configuring Eclipse Mosquitto
Eclipse Mosquitto is a lightweight, open-source MQTT broker implementing versions 5.0, 3.1.1, and 3.1 of the MQTT protocol. To configure it for both unencrypted local testing and secure production-like validation, we need to supply a custom configuration file.
Create a file named mosquitto.conf inside your C:\docker\mqtt\config\ directory. Populate it with the following production-aligned configuration:
# Config file for Eclipse Mosquitto
# Persistence settings to save retained messages and subscriptions
persistence true
persistence_location /mosquitto/data/
# Logging configuration
log_dest file /mosquitto/log/mosquitto.log
log_dest stdout
log_type all
connection_messages true
log_timestamp true
# Default listeners
# Standard unencrypted listener for local development
listener 1883
allow_anonymous true
# WebSockets listener (optional, useful for web-based dashboards)
listener 9001
protocol websockets
allow_anonymous true
# Secure TLS listener placeholder (uncomment when certificates are added)
# listener 8883
# cafile /mosquitto/config/certs/ca.crt
# certfile /mosquitto/config/certs/server.crt
# keyfile /mosquitto/config/certs/server.key
# require_certificate false
Note: For initial testing, allow_anonymous true is enabled. In production environments, you must set this to false and enforce authentication using password files (password_file) and Access Control Lists (acl_file).
Constructing the Docker Compose Manifest
Using Docker Compose allows us to declare our broker’s network configuration, port mappings, and volume mounts reproducibly. This makes it trivial to spin the stack up or down across different developer workstations.
Create a docker-compose.yml file in the root of C:\docker\mqtt\:
version: '3.8'
services:
mosquitto:
image: eclipse-mosquitto:2.0.18
container_name: mqtt-broker
restart: unless-stopped
ports:
- "1883:1883"
- "9001:9001"
volumes:
- ./config/mosquitto.conf:/mosquitto/config/mosquitto.conf
- ./data:/mosquitto/data
- ./log:/mosquitto/log
networks:
- iot-network
healthcheck:
test: ["CMD-SHELL", "nc -z localhost 1883 || exit 1"]
interval: 10s
timeout: 5s
retries: 3
networks:
iot-network:
driver: bridge
Key Considerations in the Manifest:
- Image Pinning: We explicitly pin
eclipse-mosquitto:2.0.18rather than using thelatesttag to prevent breaking changes from upstream maintainers. - Port Mapping: Ports
1883(MQTT) and9001(WebSockets) are exposed to the host machine, allowing external IoT devices on the local network or host-based microservices to communicate with the broker. - Healthcheck: The container uses a netcat (
nc) check to ensure the MQTT port is actively accepting connections before marking the container status ashealthy.
Deploying and Verifying the Broker
With the configuration and compose manifest in place, launch the container stack in detached mode using Docker Compose:
docker compose up -d
Verify that the container is running and passes its health checks:
docker compose ps
You should see the mqtt-broker container running with a status of healthy.
Inspecting Container Logs
To confirm that Mosquitto has successfully initialized without configuration syntax errors, tail the container logs:
docker compose logs -f mosquitto
A healthy startup sequence will output lines similar to:
mqtt-broker | 1700000000: mosquitto version 2.0.18 starting
mqtt-broker | 1700000000: Config loaded from /mosquitto/config/mosquitto.conf
mqtt-broker | 1700000000: Opening IPv4 listen socket on port 1883.
mqtt-broker | 1700000000: Opening IPv4 listen socket on port 9001.
mqtt-broker | 1700000000: Mosquitto broker running.
Testing Pub/Sub Functionality
To validate that the broker is actively routing messages, we can run a dual-terminal test using Mosquitto's built-in command-line tools inside the container, or via a local client.
Terminal 1: Subscribe to a Topic
Execute an interactive shell inside the running container to run a subscriber client:
docker exec -it mqtt-broker mosquitto_sub -h localhost -p 1883 -t "iot/sensors/temperature"
Terminal 2: Publish a Message
Open a second PowerShell window, and publish a payload to the target topic:
docker exec -it mqtt-broker mosquitto_pub -h localhost -p 1883 -t "iot/sensors/temperature" -m "{\"device_id\": \"sensor-01\", \"temp\": 22.5, \"unit\": \"C\"}"
In your first terminal, you should instantly see the JSON payload printed to stdout:
{"device_id": "sensor-01", "temp": 22.5, "unit": "C"}
This confirms that the TCP loopback, internal container networking, and message broker loop are fully operational.
Hardening Security for Production-Ready Workloads
Leaving an MQTT broker open to anonymous access and unencrypted traffic (1883) is a critical security vulnerability. For development environments that mimic production, or environments exposed to local network testing, you should enable password authentication and TLS encryption.
Step 1: Implementing Password Authentication
Modify your C:\docker\mqtt\config\mosquitto.conf file to disable anonymous access and point to a password file:
allow_anonymous false
password_file /mosquitto/config/passwd
Next, generate a password file and add a user (e.g., iot_admin) using the Mosquitto password utility inside the container:
docker exec -it mqtt-broker mosquitto_passwd -c /mosquitto/config/passwd iot_admin
You will be prompted to enter and confirm a secure password. Restart the container to apply the changes:
docker compose restart mosquitto
When publishing or subscribing henceforth, you must pass authentication credentials:
docker exec -it mqtt-broker mosquitto_sub -h localhost -p 1883 -t "iot/#" -u "iot_admin" -P "your_secure_password"
Step 2: Generating Local TLS Certificates for Port 8883
For end-to-end encryption, MQTT uses TLS over port 8883. While production systems utilize certificates issued by a trusted Certificate Authority (CA) like Let's Encrypt, local development environments typically rely on a self-signed local CA.
Create a certs directory inside your configuration folder:
mkdir C:\docker\mqtt\config\certs
cd C:\docker\mqtt\config\certs
Using OpenSSL (available natively in Git Bash or WSL 2 on Windows 11), generate a Certificate Authority and server certificates:
# 1. Generate CA Private Key and Certificate
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -sha256 -days 365 -out ca.crt -subj "/CN=LocalIoT-CA"
# 2. Generate Broker Server Private Key and CSR
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=localhost"
# 3. Sign the Server Certificate with the Local CA
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -sha256
Update your mosquitto.conf to enable the TLS listener:
listener 8883
cafile /mosquitto/config/certs/ca.crt
certfile /mosquitto/config/certs/server.crt
keyfile /mosquitto/config/certs/server.key
require_certificate false
Expose port 8883 in your docker-compose.yml:
ports:
- "1883:1883"
- "8883:8883"
- "9001:9001"
Restart the stack to activate TLS encryption:
docker compose down
docker compose up -d
Performance Tuning and Troubleshooting on Windows 11
When running high-throughput IoT message brokers under Docker on Windows 11, developers may occasionally run into platform-specific performance bottlenecks.
WSL 2 Resource Constraints
If your broker experiences dropped packets or high latency under load, check your WSL 2 resource allocation. Create or edit the .wslconfig file in your Windows user profile directory (C:\Users\YourUsername\.wslconfig):
[wsl2]
memory=4GB
processors=4
swap=2GB
localhostForwarding=true
Restart WSL from PowerShell to apply changes:
wsl --shutdown
Common Troubleshooting Commands
- Port Conflicts: If port
1883is already bound (often by a natively installed Mosquitto service running on Windows), check and stop the conflicting service:Get-Service -Name *mosquitto* Stop-Service -Name mosquitto - File Permission Issues: If Mosquitto fails to start due to permission errors on configuration files mapped from the Windows host, ensure that Docker Desktop has proper file-sharing permissions configured for the
C:\docker\mqttpath via Settings > Resources > File Sharing. - Real-time Container Metrics: Monitor CPU and memory utilization of your broker container:
docker stats mqtt-broker
Conclusion
By combining Windows 11, Docker Desktop, and Eclipse Mosquitto, you have established a reliable, isolated, and production-mirrored MQTT broker environment. This configuration supports both rapid prototyping with unencrypted local sockets and rigorous security validation using access control lists and TLS encryption over port 8883. You are now equipped to connect physical microcontrollers, edge gateways, or backend microservices to your local Windows development pipeline.

