paho.mqtt.golang

The Eclipse Paho MQTT v3.1/3.1.1 client library for Go, built for fully asynchronous pub/sub messaging.

Library
Go
vv1.5.1
3,121stars
EPL-2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
76/100Good
Development Activity72
Maintenance48
Community84
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
72/100Good
Architecture80
Code Quality78
Innovation55
Learning Curve75

paho.mqtt.golang is the Go implementation of the Eclipse Paho MQTT client, giving Go applications a way to connect to any MQTT 3.1/3.1.1 broker, publish messages, and subscribe to topics. It is built around a fully asynchronous model: connection, publish, and subscribe calls return a Token immediately, and callers wait on or poll that token for completion rather than blocking the calling goroutine.

The library supports plain TCP, TLS/SSL, and WebSocket transports (including behind corporate HTTP(S) proxies via the standard proxy environment variables), automatic reconnection with configurable backoff, and pluggable message persistence through a Store interface (with in-memory and file-backed implementations provided out of the box) so in-flight QoS 1/2 messages can survive a reconnect.

As the most widely used Go MQTT client, it underpins a large share of Go-based IoT gateways, home-automation hubs, and telemetry agents that need a battle-tested, protocol-compliant way to talk to brokers like Mosquitto, EMQX, or HiveMQ.

What You Get

  • A Client interface with Connect, Publish, Subscribe, SubscribeMultiple, and Unsubscribe methods that all return a Token for non-blocking completion tracking
  • Automatic reconnection with exponential backoff (backoffController) and configurable AutoReconnect/ConnectRetry behaviour
  • Pluggable message persistence via the Store interface, with MemoryStore and FileStore implementations for surviving reconnects at QoS 1/2
  • Transport flexibility: plain tcp://, secure tls:///ssl://, and ws:///wss:// WebSocket connections, including corporate proxy support
  • Topic-based message routing through an internal router, plus AddRoute/DeleteRoute for registering handlers outside of Subscribe calls
  • Configurable logging hooks (ERROR, CRITICAL, WARN, DEBUG) for wiring the library’s internal tracing into an application’s own logger

Common Use Cases

  • Connecting Go-based IoT device agents or gateways to an MQTT broker for telemetry publishing
  • Building home-automation or industrial-automation hubs that subscribe to sensor/actuator topics
  • Bridging services that need reliable pub/sub messaging without running a full message-queue cluster
  • Implementing MQTT-based command-and-control channels between backend services and edge devices
  • Prototyping and testing MQTT brokers or infrastructure using the sample publishers/subscribers in cmd/

Under The Hood

Architecture The library is organized as a layered pub/sub client: client.go defines the public Client interface and the internal client struct that owns connection lifecycle (Connect, reconnect, attemptConnection), background comms workers (startCommsWorkers/stopCommsWorkers spin up goroutines for inbound/outbound packet handling), and the public Publish/Subscribe/Unsubscribe surface; wire-format encoding and decoding is fully isolated in the packets/ subpackage (one file per MQTT control packet type — connect.go, publish.go, suback.go, etc.), and message routing to registered callbacks goes through router.go. Persistence is abstracted behind the Store interface (store.go) with MemoryStore and FileStore as swappable implementations, and token.go implements the async completion primitive (Token/PacketAndToken) that every public method returns instead of blocking. This separation means the transport, protocol-encoding, routing, and persistence concerns can each be reasoned about (and replaced, e.g. via CustomOpenConnectionFn) independently — changing the core packets.ControlPacket abstraction would ripple through nearly every file, since it is the shared currency between the client, store, and router layers.

Tech Stack Written in Go (module targets Go 1.25) with a deliberately small dependency footprint: github.com/gorilla/websocket for the WebSocket transport, golang.org/x/net for proxy-aware dialing, and golang.org/x/sync/semaphore for bounding concurrent work in the comms workers. There is no external build tooling beyond the standard go build/go test toolchain, and the package is consumed directly via Go modules (go get github.com/eclipse/paho.mqtt.golang). A CodeQL workflow is configured for static security analysis in CI.

Code Quality The repository has an unusually large and clearly segmented test suite for a library of this size — unit tests are prefixed unit_*_test.go (client, options, store, router, topic, message IDs, ping, status, net) and are separated from full-verification-tests (FVT, requiring a live broker) in fvt_*_test.go, plus a dedicated packets_test.go for wire-format round-tripping. Error handling favours explicit typed error values (errors.New, wrapped context) over panics, and public types are documented with Go-idiomatic doc comments throughout client.go and options.go. Concurrency-sensitive state (connection status, backoff tracking) is guarded with sync.RWMutex/sync/atomic, reflecting the library’s asynchronous, multi-goroutine design.

API Design The public API is intentionally small and consistent: every state-changing call (Connect, Publish, Subscribe, Unsubscribe) returns a Token, so callers learn one waiting pattern (token.Wait() or <-token.Done()) instead of a different completion mechanism per call. Getting started requires only a ClientOptions builder and NewClient, and the cmd/ directory ships runnable samples (simple, ssl, routing, custom_store, stdin/stdout pub-sub) that double as executable documentation. The one rough edge, called out explicitly in the README’s troubleshooting section, is that the async model makes it easy to forget to check token.Error(), and message handlers must not block unless SetOrderMatters(false) is configured.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search