Comqtt is an embeddable MQTT broker with a Gossip and Raft cluster
A lightweight, high-performance go mqtt server(v3.0|v3.1.1|v5.0) supporting distributed cluster
At a glance
- What is it?
- Comqtt is a Go implementation of an MQTT broker that speaks version 3.0, 3.1.1 and 5.0, runs TCP, WebSocket, QUIC and dashboard listeners, and can be used either as a standalone binary or linked into your own program. Clustering uses memberlist for membership and Raft for consensus, and the plugin model covers authentication, storage and bridging to Kafka.
- Who is it for?
- Adopt Comqtt when you want an MQTT broker you can embed in your own Go service, or when you need the v5.0 feature set on a lightweight implementation, and you are prepared to run the cluster yourself. Do not adopt it because it is small, since the clustering and plugin machinery is a real operational surface.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A broker you can also link into your own program
Comqtt is an embeddable high-performance MQTT broker server written in Go, supporting a distributed cluster, and compliant with the MQTT v3.0 and v3.1.1 and v5.0 specification for the development of IoT and smart home projects.
The server can be used either as a standalone binary or embedded as a library in your own projects, and that second option is the interesting one. A broker you link into your service removes a network hop and a process to supervise, and for an IoT product where the broker is a component rather than an infrastructure service, that is a real simplification.
The claim about throughput is that the message throughput is comparable with everyone's favourites such as Mosquitto, Mosca and VerneMQ, which is a comparison rather than a number, so it tells you where to position it rather than what to expect.
The implementation is Go with the module path github.com/wind-c/comqtt/v2, so the major version is in the import path. The licence is MIT, the last push was on 2026-10-15, and the recent releases are v2.6.5 from 2026-07-11, v2.6.4 and v2.6.3 from 2026-05-13.
The project is explicit about what MQTT is for, a publish and subscribe messaging protocol designed for constrained devices and low-bandwidth, high-latency or unreliable networks, which is the constraint set that shapes every design decision in a broker.
Four listeners, and a dashboard that is on by default
The feature list opens with protocol compliance and then the listeners.
Full MQTTv5 feature compliance, with compatibility for MQTT v3.1.1 and v3.0.0. And TCP, Websocket, QUIC including SSL/TLS, and dashboard listeners.
The quick start gives the port numbers. The single entry point exposes tcp on 1883, websocket on 1882, and the dashboard on 8080.
The QUIC listener is the least conventional of the three, and it is a good fit for the constrained device case, because QUIC gives you encryption and connection migration without a separate TLS stack or a separate port for the secure variant. The README also lists file-based configuration for the server, auth, storage and bridge, with a link to the config examples.
The dashboard is worth a separate note, because of the default. The built-in web dashboard for broker monitoring and management is enabled by default, and the default login is admin with the password admin. That is fine on a laptop and wrong on anything reachable, and it is the first thing to change in any deployment that is not on your own machine, because the dashboard exposes client information and cluster control.
The cluster is memberlist for membership and Raft for consensus
Cluster support is based on Gossip and Raft, with a link to the cluster README, and the dependency list shows exactly what that means.
hashicorp/memberlist is the gossip layer, and hashicorp/serf appears alongside it in the dependency list. On top of that sits hashicorp/raft at 1.7.3, with hashicorp/raft-boltdb for the log storage. etcd's own raft implementation and bbolt are also in the dependency list, along with the etcd client and server packages.
The two layers do different jobs, and the API reflects that. The cluster endpoints are mostly about membership and about the state that has to be identical everywhere. GET /api/v1/cluster/nodes lists all the nodes, POST adds one with a name and an address, and there is a stat endpoint for the online count across the cluster. There is also a graceful leave endpoint, DELETE /api/v1/node/{name}, and the reason given is practical: leaving the cluster gracefully exits it, and exiting the cluster actively can prevent other nodes from constantly attempting to connect to that node.
That last detail is the kind of operational note that saves an outage, because a node that dies without leaving makes the rest of the cluster try to reach it until it is evicted.
A hook pattern for auth, storage and bridging
The plugin model is the part that makes the broker extensible, and the readme describes it as a hook design pattern that makes it easy to develop plugins for auth, bridge and storage.
The auth and ACL plugin supports Redis, HTTP, MySQL and PostgreSQL. The storage choices for single machine mode are local storage with BBolt, Badger and Redis. And packets are bridged to Kafka according to the configured rule.
The dependencies back each of those up. go-redis for Redis, the MySQL driver and pgx for the SQL databases, bbolt and badgerhold for the local stores, and segmentio/kafka-go for the bridge. The Kafka bridge is a distinctive choice, since most brokers bridge to other brokers and this one bridges to a log, which is what you want when the consumers are analytics pipelines rather than devices.
The pattern is the same for all three, which is what makes it a pattern rather than three features. Your plugin implements an interface, the broker calls it, and the storage, the authentication decision and the bridge rule all come out through the same seam. That also means a plugin can be developed without touching the broker, which is the property that decides whether an extension point is usable.
The REST API, and the dashboard credentials
The REST API is listed endpoint by endpoint, and the shape of it tells you what an operator is expected to do.
There are single node endpoints for the configuration, the overall server information, the online count, a client by id, and the blacklist. A blacklist can be posted for a client, which disconnects it and adds it, and deleted to remove it. There is a publish endpoint, POST /api/v1/mqtt/message, whose body carries a topic name, a payload, a retain flag and a qos.
Then there are the cluster variants, and the difference is instructive. The cluster blacklist endpoint adds or removes a client id on all nodes in the cluster, and the cluster client lookup searches from all nodes rather than from the local one. So the same logical operation is exposed once per node and once across the cluster, which is a sensible API design for a system that is distributed.
The dashboard default of admin and admin is the one thing here to fix. The endpoints include publishing messages and disconnecting clients, and both of those are actions you do not want reachable with published default credentials on a network that other people can see.
The readme also notes that the dashboard is enabled by default, so it is not a setting you have to turn on, it is a setting you have to turn off or secure.
YAML configuration with environment variable overrides
The configuration is a YAML file, and there is an override mechanism that is worth reading because it is more disciplined than most.
When starting with a configuration file, any scalar value can be overridden by an environment variable at deploy time, for example to inject a dynamic Kubernetes pod IP as cluster.bind-addr.
The naming rule is exact. The env var name is COMQTT_ plus the dotted yaml path of the field, uppercased with dashes replaced by underscores and segments joined by underscores. So cluster.bind-addr becomes COMQTT_CLUSTER_BIND_ADDR, mqtt.tcp becomes COMQTT_MQTT_TCP, redis.options.addr becomes COMQTT_REDIS_OPTIONS_ADDR, and dashboard.secret-file becomes COMQTT_DASHBOARD_SECRET_FILE.
There are two limits. The supported field kinds are string, int or uint, and bool, so slices and maps such as cluster.members cannot be overridden by an environment variable. And a value is overridden only if the env var is set, where an empty string explicitly clears the YAML value, which is a way of saying that an unset variable and an empty one are not the same thing.
The example shows the pattern in use, with two variables and the config file argument.
COMQTT_CLUSTER_BIND_ADDR=10.244.0.17 \
COMQTT_CLUSTER_RAFT_BOOTSTRAP=true \
./comqtt --conf=./config/node1.ymlThat matters for a clustered deployment, where the bind address is a pod IP that is not known until the pod starts, and where the bootstrap flag decides whether a node seeds the Raft group or joins an existing one.
Two binaries, one image, and a compose file for the databases
The Dockerfile builds two binaries from the same source and ships both in a minimal image.
The builder is golang:1.24-alpine3.20, and the build step produces a single node binary and a cluster binary.
RUN go build -o /app/comqtt ./cmd/single
RUN go build -o /app/comqtt-cluster ./cmd/clusterThe runtime stage is plain alpine with the two binaries copied in and the entrypoint set to the single node one. So the image is a static Go binary on a minimal base, and the cluster variant is there for the deployment that needs it.
The compose file at the root of the repository is not for the broker. It starts MySQL 8.0 and PostgreSQL 16 with the init scripts from the auth plugin test data mounted, which means it exists to run the authentication plugin's tests against real databases rather than mocks.
That is a good sign about the testing. An auth plugin is exactly the code where a mock hides the failure, because the mock returns the answer the test expects and the real database returns the answer the query produces.
The top level listing shows the rest of the structure, with mqtt/ for the protocol implementation, cluster/ for the distributed parts, cmd/ for the entry points, plugin/ for the extensions, config/ for the configuration examples, dashboard/ for the web interface, deploy/ for the deployment artefacts, docker/ for the container material, and a Dockerfile, a Dockerfile.goreleaser, a Procfile and a .goreleaser.yaml for the release pipeline.
Editorial conclusion
Adopt Comqtt when you want an MQTT broker you can embed in your own Go service, or when you need the v5.0 feature set on a lightweight implementation, and you are prepared to run the cluster yourself. Do not adopt it because it is small, since the clustering and plugin machinery is a real operational surface. Verify first that your clients speak the protocol version you enable, that you change the dashboard's default credentials, and that the storage backend you choose is one of the supported ones for your data volume, since the single machine mode lists only a small set of them.
Frequently asked questions
What is Comqtt?
It is an embeddable high-performance MQTT broker written in Go, compliant with the MQTT v3.0, v3.1.1 and v5.0 specifications, supporting a distributed cluster. It runs as a standalone binary or is linked into your own program as a library.
Which protocols and ports does Comqtt support?
TCP, WebSocket, QUIC including SSL/TLS, and a dashboard listener. The single node entry point exposes tcp on 1883, websocket on 1882 and the dashboard on 8080.
How does Comqtt cluster nodes?
With Gossip for membership through hashicorp/memberlist and Raft for consensus through hashicorp/raft with a bbolt log store. The cluster API covers listing and adding nodes, the online count across the cluster, and a graceful leave endpoint that stops other nodes from retrying a dead node.
Which plugins does Comqtt support?
Auth and ACL plugins backed by Redis, HTTP, MySQL and PostgreSQL, storage for single machine mode with BBolt, Badger and Redis, and a bridge that forwards packets to Kafka according to a configured rule. The plugin system is described as a hook design pattern shared by auth, bridge and storage.
How do I override Comqtt configuration at deploy time?
With environment variables named COMQTT_ plus the uppercased dotted YAML path of the field, with dashes replaced by underscores, so cluster.bind-addr becomes COMQTT_CLUSTER_BIND_ADDR. Only string, int, uint and bool fields can be overridden, and an empty value explicitly clears the YAML value.
What are the default credentials for the Comqtt dashboard?
The built-in dashboard is enabled by default and the default login is admin with the password admin, so it needs changing before the broker is reachable by anything but you.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/wind-c-comqtt)Was this useful?