Gmqtt: an MQTT broker in Go with a plug-in architecture
Gmqtt is a flexible, high-performance MQTT broker library that fully implements the MQTT protocol V3.x and V5 in golang
At a glance
- What is it?
- A Go broker implementing MQTT V3.x and V5 with TLS, websockets, Redis-backed session persistence, Prometheus metrics, gRPC and REST admin APIs and a federation plugin for clustering. The README states plainly that the project is less maintained due to personal reasons and should be evaluated and tested carefully before production use.
- Who is it for?
- Gmqtt fits a Go team that needs an MQTT broker it can extend from inside its own process, where a hook for authentication, topic ACLs or will-message handling is easier to write than a separate authorisation service. It does not fit a team that needs a maintained upstream, because the README says the project is less maintained due to personal reasons, the last push was on 2026-04-05 and the newest tag is v0.5.0 from 2022-12-11.
- 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?
- Activity is slowing. The repository last received commits 6 months 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
The project state section comes before the feature list
The README puts a section titled Project state directly under the title, and it is the most important paragraph in the document. It says the project is less maintained due to personal reasons, and offers the information for people who want to use it.
The rest of the section is unusually honest about what that means. Gmqtt was used in production and worked well. The production environment was serving hundreds of clients, or maybe thousands or ten thousands now, and each client published a QoS 1 message to report their state every fifteen seconds, with subscribers on the cloud storing that state into a persistence backend. All the clients were non-persistent sessions using the v3.1.1 protocol.
The final line is the one to quote when someone asks whether to deploy it: it is suggested to evaluate and test carefully before running in your production environment.
The dates back that up. The last push was on 2026-04-05, and the release tags are v0.5.0 from 2022-12-11, v0.4.1 from 2021-07-21 and v0.4.0 from 2021-07-02. So the tags are more than three years behind the branch head, and the head itself has not moved in over half a year.
The library is MIT licensed and the primary language is Go, with a `go.mod` that declares `go 1.26.1`, which is a very recent toolchain floor. The dependency list is long and modern, with cobra for the command line, gorilla/websocket, redigo for Redis, prometheus client_golang, gRPC with the grpc-gateway, zap for logging and testify for tests.
The plugin mechanism and the extension interface
The feature list leads with hooks and plugins, and that is the architectural centre of the project.
Hooks are the fine-grained mechanism. The README lists nineteen of them, and the table pairs each with its hooking point and possible usages. The ones that matter for access control are `OnAccept`, fired when a TCP connection is accepted, with connection rate limiting and IP allow or block lists as the suggested uses, though it is not supported over websocket. `OnSubscribe` and `OnUnsubscribe` fire when the corresponding packet is received, and their listed usages are subscribe access control and modifying subscriptions. `OnMsgArrived` fires on a publish packet, for publish access control and modifying the message before delivery. `OnWillPublish` fires when a client is about to deliver a will message, and the message can be modified or dropped.
The MQTT 5 specific hooks are `OnEnhancedAuth`, for a connect packet with an AuthMethod property, and `OnReAuth`, for an auth packet. `OnBasicAuth` covers the older connect-without-AuthMethod case, which is the v3 path.
Plugins are the coarser mechanism, and the README points at `server/plugin.go` and the `plugin/` directory. Plugins in the tree include `auth`, `prometheus`, `admin` and `federation`.
The `admin` plugin provides gRPC and REST APIs to interact with the server, and the `prometheus` plugin provides the metrics. The `Server` interface in `server/server.go` is what lets an extension reach into the running broker, so the README says an extension or plugin can publish a message or add or remove a subscription through a function call.
The `federation` plugin is the clustering mechanism, and it comes with a warning in capitals in the feature list: it is an experimental feature that has never been used in a production environment. The README describes it as providing clustering, with examples and details in the plugin's own documentation.
Running the broker and the configuration file
To get started, gmqtt is compiled from source and needs a working Go environment.
$ git clone https://github.com/DrmagicE/gmqtt
$ cd gmqtt/cmd/gmqttd
$ go run . start -c default_config.ymlThe `-c` flag defines the configuration path, and if it is not set gmqtt reads `$HOME/gmqtt.yml` as the default. The sample configuration lives at `cmd/gmqttd/default_config.yml`.
With the default configuration the broker listens on 1883 for the TCP server and 8883 for the websocket server, with the `admin` and `prometheus` plugins loaded. The plugin loading order is a configuration key, and the auth example shows it:
plugin_order:
- auth
- prometheus
- adminThe order matters for the auth plugin in particular, since it has to be in place before clients try to connect.
A Dockerfile is at the repository root, and the run command exposes five ports:
$ docker build -t gmqtt .
$ docker run -p 1883:1883 -p 8883:8883 -p 8082:8082 -p 8083:8083 -p 8084:8084 gmqttThe image is a two-stage build on the alpine base, running `make binary` in a golang builder and copying the resulting `gmqttd` into a second stage, with the default configuration copied to `/etc/gmqtt/gmqttd.yml`. The exposed ports are 1883 and 8883 for the broker, 8082 and 8083 for the admin API, and 8084.
The Makefile is a conventional Go project Makefile with `fmt`, `lint`, `vet`, `test`, `test-cover` and `build` targets, plus a `tools` target that installs protoc-gen-grpc-gateway, protoc-gen-openapiv2, protoc-gen-validate, protoc-gen-go, protoc-gen-go-grpc, go-swagger and mockgen, which tells you the gRPC and REST surface is generated from protobuf definitions rather than hand-written.
Session persistence with Redis, and the in-memory default
Gmqtt stores session data in memory by default, and the README recommends it that way because of the good performance. The trade is that the session data is lost after the broker restarts.
To avoid that, Redis is supported as the backend store:
persistence:
type: redis
redis:
# redis server address
addr: "127.0.0.1:6379"
# the maximum number of idle connections in the redis connection pool
max_idle: 1000
# the maximum number of connections allocated by the redis connection pool at a given time.
# If zero, there is no limit on the number of connections in the pool.
max_active: 0
# the connection idle timeout, connection will be closed after remaining idle for this duration. If the value is zero, idle connections are not closed
idle_timeout: 240s
password: ""
# the number of the redis database
database: 0Redis is currently the only supported backend. The configuration surface is a standard redigo pool, and the comments in the sample spell out the semantics of each knob.
The `persistence/` directory at the repository root holds the implementation, and the `session.go` and `subscription.go` files at the top level are the session model. The `retained/` and `topicalias/` directories are separate concerns, for retained messages and topic aliases, and the `pkg/` directory holds supporting packages.
The distinction between memory and Redis matters mostly for persistent sessions. The production deployment described in the README used non-persistent sessions throughout, which is the configuration where losing session state on restart costs the least, since the client simply resubscribes and re-reports.
Authentication through the admin API, with a hashed password
Authentication is provided by the `auth` plugin as a simple username and password mechanism, and it is not enabled in the default configuration.
When it is enabled, every client needs an account to connect. Accounts are added through the HTTP API:
# Create: username = user1, password = user1pass
$ curl -X POST -d '{"password":"user1pass"}' 127.0.0.1:8083/v1/accounts/user1
{}
# Query
$ curl 127.0.0.1:8083/v1/accounts/user1
{"account":{"username":"user1","password":"20a0db53bc1881a7f739cd956b740039"}}The response to the query shows the password as a 32-character hex string, which is an MD5 digest. The account is created with a plain password over the API and stored as a digest.
Two things follow. First, the API is unauthenticated on the example, since the command posts a password with no credentials of its own, so the admin HTTP port must not be exposed to an untrusted network. Second, the password is returned as a single 32-character hex digest with no visible salt, which is a weaker storage scheme than a modern password hash with a per-account salt.
The swagger documentation for the auth plugin lives in the repository at `plugin/auth/swagger`, and the README's example output is the `{}` on the create call, meaning the create endpoint returns an empty body.
For anything beyond username and password, the hooks are the extension point. `OnBasicAuth`, `OnEnhancedAuth` and `OnReAuth` are where a custom authentication scheme, including one backed by an external service, would be implemented, and the same is true of topic-level access control through `OnSubscribe`, `OnUnsubscribe` and `OnMsgArrived`.
Testing, the toolchain and the build plumbing
The unit tests are run with the race detector enabled across the whole module:
$ go test -race ./...That is the right choice for a broker, where the sessions and subscriptions are shared mutable state across goroutines, and there is a `go_test.sh` script at the repository root alongside a `Makefile` target. The README also points to an integration test section, and the `go.mod` includes `go.uber.org/mock` for generated mocks and `go-swagger` for the API spec.
The module requires Go 1.26.1, and the dependency set is the modern one: `google.golang.org/grpc` at 1.79.3, the grpc-gateway v2 at 2.28.0, `prometheus/client_golang`, `gorilla/websocket` at 1.4.2, `gomodule/redigo` at 1.8.2, `spf13/cobra` at 1.10.2 and `golang.org/x/crypto` at 0.49.0.
The Makefile derives the version from git, with `git describe --tags --always --dirty --match=v*` falling back to a `.version` file and then to `v0`, so a build from a dirty working tree is marked as such. The `plugin_generate.go` file and `plugin_imports.yml` at the root suggest that the plugin wiring is generated rather than maintained by hand across every plugin's imports.
The `config/`, `server/`, `cmd/`, `tools/` and `plugin/` directories are the top level of the source, and the `docs/` equivalent is godoc, linked from the README.
Where Gmqtt is the wrong choice
The first wrong case is a team that needs a maintained broker. The README's project state section says the project is less maintained due to personal reasons, the last push was on 2026-04-05, and the newest release tag is from 2022-12-11. A broker is infrastructure that has to keep running, and a project with that maintenance profile is a decision to take on yourself.
The second wrong case is clustering. The federation plugin is labelled experimental in the feature list and has never been used in a production environment, so a deployment that needs multi-node MQTT has to either build that path themselves or pick a different broker.
The third is a security-sensitive deployment relying on the built-in auth. The password is stored as an unsalted MD5 digest, the admin API that creates accounts is unauthenticated in the documented example, and there is no TLS client-certificate authentication described. The hooks let you replace the mechanism, but writing and owning that code is the cost.
The fourth is a project that needs MQTT 5 features beyond the basics, or broker features the feature list does not mention, such as shared subscriptions, retained message handling with the semantics you expect, or a bridge to another protocol. The README lists what is there, and the list is not long.
What the project offers instead is a genuinely embeddable broker with a plugin API, a `Server` interface for extensions, and a hook for almost every point in the connection lifecycle. For a Go team that wants to put their own authentication, ACL logic or instrumentation inside the broker process, that combination is still hard to find elsewhere, provided you are prepared to own it.
Editorial conclusion
Gmqtt fits a Go team that needs an MQTT broker it can extend from inside its own process, where a hook for authentication, topic ACLs or will-message handling is easier to write than a separate authorisation service. It does not fit a team that needs a maintained upstream, because the README says the project is less maintained due to personal reasons, the last push was on 2026-04-05 and the newest tag is v0.5.0 from 2022-12-11. Before adopting it, read the project state section rather than the feature list, and if you rely on clustering, remember the README's warning that the federation plugin is experimental and has never been used in a production environment.
Frequently asked questions
How do I start the Gmqtt broker?
Clone the repository, change into `gmqtt/cmd/gmqttd` and run `go run . start -c default_config.yml`. The `-c` flag sets the configuration path, and without it gmqtt reads `$HOME/gmqtt.yml`.
Is Gmqtt still maintained?
The README states the project is less maintained due to personal reasons, and suggests evaluating and testing carefully before running it in a production environment. The last push was on 2026-04-05 and the most recent release tag is v0.5.0 from 2022-12-11.
How does Gmqtt store session data?
In memory by default, which the README recommends for performance, with the trade that session data is lost on broker restart. Redis is supported as an alternative backend through the `persistence` section of the configuration file, and it is currently the only supported backend.
How do I enable authentication in Gmqtt?
Enable the `auth` plugin in the `plugin_order` configuration list. It is not enabled in the default configuration, and once enabled every client needs an account, which you create through the admin HTTP API.
Does Gmqtt support clustering?
A federation plugin provides clustering, but the README warns in capitals that it is an experimental feature that has never been used in a production environment.
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/drmagice-gmqtt)Was this useful?