Library / SDK
eclipse-paho/paho.mqtt.c avatar
eclipse-paho/paho.mqtt.c

paho.mqtt.c: four libraries, two transports, and two build flags you must not miss

An Eclipse Paho C client library for MQTT for Windows, Linux and MacOS. API documentation: https://eclipse-paho.github.io/paho.mqtt.c/

2,373 stars1,190 forksCNOASSERTION

At a glance

What is it?
The Eclipse Paho C client connects applications to an MQTT broker with synchronous or asynchronous APIs and TLS, Unix sockets or websockets, but TLS and Unix-domain sockets are opt-in at build time and the SSL option still requires a runtime struct field. It is dual-licensed EPL-2.0 or EDL-1.0 and its CI badges still point at Travis.
Who is it for?
Adopt paho.mqtt.c when you are writing a C or C++ process that needs MQTT and you value a client with TLS and Unix-socket transports, Doxygen docs and shipped sample binaries. Do not adopt it from a stock build for a TLS-only broker, on Windows if you need a local Unix socket, or for MQTT-SN over serial.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 21 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Four libraries behind two API names

The most confusing thing about this project is structural, and it comes first because everything else follows from it. The Paho C client comprises four variant libraries, each available shared or static, and they come in two pairs.

`paho-mqtt3a` is asynchronous, through the `MQTTAsync` API. `paho-mqtt3as` is the same with SSL/TLS added. `paho-mqtt3c` is described as classic or synchronous, through the `MQTTClient` API, and `paho-mqtt3cs` is that with SSL/TLS.

So there are two decisions before you write a line of code. Which concurrency model, and whether you want the transport security compiled in. The README links an article titled which Paho C API to use, with some history, for context, which is the right thing to read before choosing, because the asynchronous API predates the synchronous one and the naming carries that history.

What the library does with either is the same job: connect applications to an MQTT broker to publish messages, subscribe to topics and receive published messages. The README states synchronous and various asynchronous programming models are supported, and both MQTT 3.1.1 and MQTT 5.0 are documented as the standards in play, with links to the OASIS specifications and to HiveMQ's introduction for background.

The synchronous versus asynchronous split is the more consequential of the two. A blocking publish-and-wait call is easier to reason about and harder to run well under load; the asynchronous API exists for the other case.

The connect URI picks the transport, and two of them are build-time opt-ins

The transport is selected by a URI in the connect options rather than by a separate configuration struct, and the scheme table in the README is worth reading as a build-feature checklist.

`mqtt://` and `tcp://` are identical and mean insecure TCP. `mqtts://` and `ssl://` are identical and mean SSL/TLS. `ws://` and `wss://` are websockets, insecure and secure. And `unix://` is a Unix-domain socket.

The catch is that two of those only exist if you asked for them at build time. The README is emphatic: use of any secure connect option requires compiling the library with the `PAHO_WITH_SSL=TRUE` CMake option to include OpenSSL, and in addition you must specify `ssl_options` when you connect, meaning an instance of `ssl_options` has to be added to the `connect_options` when calling `connect()`.

Two conditions, one build flag and one runtime struct field. Miss the second and you have a TLS-capable library that still fails to negotiate, and the failure looks like a configuration bug rather than a missing argument.

Unix-domain sockets need `PAHO_WITH_UNIX_SOCKETS=TRUE`, and the README restricts them to nix-style systems like Linux and macOS. That sentence also contains a typo, vailable instead of available, and the URI example above it is missing its closing quote. Small things, but they are in the same paragraph as the build flags, which is where a reader is least likely to be proofreading.

Tracing without a debugger

A C library talking to a network socket has no console to print to, so the debugging story here is environment variables rather than log calls in your code.

`MQTT_C_CLIENT_TRACE` switches tracing on. A value of `ON` traces to stdout, and any other value should specify a file to trace to.

`MQTT_C_CLIENT_TRACE_LEVEL` controls verbosity, with valid values ERROR, PROTOCOL, MINIMUM, MEDIUM and MAXIMUM, listed from least to most verbose. PROTOCOL is the interesting one, since it traces the MQTT packets themselves rather than the client's internal state.

`MQTT_C_CLIENT_TRACE_MAX_LINES` caps the number of trace lines output, which is what keeps a MAXIMUM level from producing a log that fills a disk.

bash
export MQTT_C_CLIENT_TRACE=ON
export MQTT_C_CLIENT_TRACE_LEVEL=PROTOCOL

This is a genuinely useful feature and it is the only observability the library offers. There is no callback or hook for structured diagnostics, no metrics interface, and no statement in the README about what tracing does to throughput. If you need to know why a client disconnected in production, this is the tool, and you should assume to enable it selectively rather than by default.

Building on Debian with CMake

The README documents a CMake build with no single build command, instead naming the tools it needs: CMake, GNU Make or Ninja, and a conforming C compiler such as gcc or Clang.

On Debian-based systems that translates to a package install.

bash
apt-get install build-essential gcc make cmake cmake-gui cmake-curses-gui

Two optional pieces follow. TLS support needs the OpenSSL libraries and headers.

bash
apt-get install libssl-dev

And generating the Doxygen documentation needs doxygen, optionally with graphviz.

bash
apt-get install doxygen graphviz

If you intend to build a Debian package from the source rather than just compile it, the additional set is fakeroot, devscripts, dh-make and lsb-release.

bash
apt-get install fakeroot devscripts dh-make lsb-release

The platform list is broader than the badge suggests. The build process supports a number of Linux flavors including ARM and s390, plus OS X, AIX, Solaris and Windows. API documentation is published online and can also be produced by building the Doxygen docs in the `doc` directory, and the Makefile adds a note that on OS X you need XCode and its command-line tools installed.

Three build systems and version files in one repository

The root carries `CMakeLists.txt`, a `Makefile`, an Ant `build.xml`, a Windows `cbuild.bat` and a `cmake-build.sh`. That is five entry points, which is a lot of surface for a project whose recommended path is CMake.

The Makefile is the oldest and the most revealing. It reads the version from three separate files rather than hardcoding it.

makefile
MAJOR_VERSION := $(shell cat version.major)
MINOR_VERSION := $(shell cat version.minor)
PATCH_VERSION := $(shell cat version.patch)

`version.major`, `version.minor` and `version.patch` sit in the repository root, so the version lives in the filesystem and CMake, Make and Ant all read the same source. The Makefile also declares `SHELL = /bin/sh`, defaults the build type to debug, and detects the platform by branching on `$(OS)` equal to `Windows_NT`, in which case it uses `PROCESSOR_ARCHITECTURE`, otherwise `uname -s` and `uname -m`, with a special case normalising `linux` to `Linux`.

The rest of the root tells you about the project's institutional history. There is `.gitreview` for Gerrit review, `appveyor.yml` and `.travis.yml` for continuous integration, `deploy_rsa.enc` for release signing, an `android/` directory, a `dist/` directory, and `SECURITY.md` and `CODE_OF_CONDUCT.md`. Eclipse project conventions, all of it, several of them older than the tools they configure.

EPL-2.0 with an EDL-1.0 alternative

The repository metadata classifies the licence as a custom licence GitHub cannot categorise, which sounds alarming until you read the Makefile header. The source is made available under the terms of the Eclipse Public License v2.0 and the Eclipse Distribution License v1.0 which accompany the distribution.

Both licence texts ship in the repository root, as `epl-v20` and `edl-v10`, with `LICENSE` and `NOTICE` alongside them. The header of the Makefile states the dual terms and links to the Eclipse legal page for EPL-2.0 and to the EDL page for EDL-1.0.

So there is nothing hidden here. This is the standard Eclipse dual-licence pattern: a weak-copyleft file-level licence, EPL-2.0, or the permissive Eclipse Distribution License as an alternative, and you pick. GitHub cannot classify it because EPL-2.0 is not on its list of recognised licences, not because the terms are unusual for an Eclipse project.

The practical question for a commercial deployment is which of the two obligations you can live with, and that depends on whether you modify the library, redistribute it, or only link against it. This is not legal advice; read `epl-v20` and `edl-v10` and decide with your own counsel.

The sample utilities, and choosing sync over async

Before integrating the library, you can test a broker with what already ships. The README lists the samples, present both in the Doxygen docs and in `src/samples`.

`paho_c_pub.c` and `paho_c_sub.c` are command-line utilities to publish and subscribe, with `-h` giving help. `paho_cs_pub.c` and `paho_cs_sub.c` are the same built on the `MQTTClient` API. `MQTTClient_publish.c`, `MQTTClient_subscribe.c` and `MQTTClient_publish_async.c` are simple code examples, and `MQTTAsync_publish.c` and `MQTTAsync_subscribe.c` cover the asynchronous side.

Running the command-line utilities is the genuine alternative to linking the library at all. You get a publish and subscribe pair with no code, no build integration and no dependency in your project, which is exactly right for checking whether a broker accepts connections, whether TLS is negotiated, and whether a topic carries what you expect. What you give up is any programmatic control, which is the entire point of the library once you are past that stage.

The other decision is the API. The classic synchronous `MQTTClient` blocks until an operation completes, which keeps control flow readable and makes error handling a return code. The asynchronous `MQTTAsync` delivers through callbacks, which is what you want when a stalled publish must not hold a thread. Both are supported, both are documented, and the README's linked history article exists because this choice was contested.

Where paho.mqtt.c is the wrong choice

Four limitations are stated or implied by the README, and one is a design boundary rather than a missing feature.

TLS is not on by default. You compile with `PAHO_WITH_SSL=TRUE` and then still must supply `ssl_options` at connect time, so a stock build cannot talk to a broker that requires TLS at all. If your deployment is TLS-only, a build with the option off simply cannot connect, and the README does not say the library fails gracefully.

Unix-domain sockets are not portable. The `PAHO_WITH_UNIX_SOCKETS=TRUE` option only works on nix-style systems, and the README says so explicitly and in the same breath says it is not available on Windows. Windows gets TCP and websockets, which is fine, but there is no local socket.

MQTT-SN is not here. The standards linked are MQTT 3.1.1 and MQTT 5.0, and the repository contains nothing about the SN variant used over serial links, so a battery-powered sensor deployment is out of scope.

The language boundary is the real one. This is a C library, so every binding in another language wraps the same four libraries and inherits their constraints, and the project itself points at paho.mqtt.c as a client for Windows, Linux and macOS without offering a managed alternative. If your runtime is not a C process, the cost is a native dependency in your build, a shared library to ship, and a blocking C API to bind. That trade is worth making for an embedded device or a hard real-time process, and questionable for a server application with a mature client library already in its language.

Editorial conclusion

Adopt paho.mqtt.c when you are writing a C or C++ process that needs MQTT and you value a client with TLS and Unix-socket transports, Doxygen docs and shipped sample binaries. Do not adopt it from a stock build for a TLS-only broker, on Windows if you need a local Unix socket, or for MQTT-SN over serial. Verify first that your build sets PAHO_WITH_SSL=TRUE and that every connect call passes ssl_options, since the README requires both, and choose between the blocking MQTTClient and the callback-based MQTTAsync before writing the first publish.

Frequently asked questions

How do I enable SSL/TLS in paho.mqtt.c?

Compile the library with the PAHO_WITH_SSL=TRUE CMake option to include OpenSSL, using mqtts:// or ssl:// in the connect URI. The README also states you must add an ssl_options instance to connect_options when calling connect().

What is the difference between MQTTClient and MQTTAsync?

The synchronous or classic API is called MQTTClient and blocks until an operation completes, while the asynchronous API is MQTTAsync and reports back through callbacks. Both exist in shared and static builds, with and without SSL/TLS, giving four libraries in total.

Which MQTT versions does the Paho C client support?

The README links the OASIS specifications for both MQTT 3.1.1 and MQTT 5.0. The client library supports TCP, SSL/TLS, Unix-domain sockets and websockets in both secure and insecure forms.

How do I turn on debug tracing in paho.mqtt.c?

Set MQTT_C_CLIENT_TRACE to ON to trace to stdout or to a filename, MQTT_C_CLIENT_TRACE_LEVEL to one of ERROR, PROTOCOL, MINIMUM, MEDIUM or MAXIMUM, and optionally MQTT_C_CLIENT_TRACE_MAX_LINES to cap the output length.

Can I test an MQTT broker without writing code?

Yes. The repository ships command-line utilities paho_c_pub.c and paho_c_sub.c for publishing and subscribing with -h giving help, plus paho_cs_pub.c and paho_cs_sub.c built on the MQTTClient API.

What licence does paho.mqtt.c use?

A dual Eclipse licence: the Eclipse Public License v2.0 or the Eclipse Distribution License v1.0, both shipped in the repository root as epl-v20 and edl-v10. That pairing is why GitHub cannot classify it. Read the files for the terms; this is not legal advice.

Official sources

  1. eclipse-paho/paho.mqtt.c on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/eclipse-paho-paho-mqtt-c.svg)](https://hysenlabs.com/projects/eclipse-paho-paho-mqtt-c)