Skip to main content

mqtt-client

An async, tokio-based MQTT 3.1.1 / MQTT 5.0 client, and the wire-protocol codec shared with mqtt-broker. Exposed to Kotlin, Swift, Python, and other languages via UniFFI.

Installation

Published on crates.io as stem-mqtt-client (not mqtt-client — already taken by an unrelated project). The import path is unaffected:

cargo add stem-mqtt-client
use mqtt_client::{ConnectOptions, MqttClient, MqttVersion, QoS};

See the root README's Installation section for every other supported language (Kotlin, Swift, Python, Go, C#, Java, Dart, Node.js and Haskell).

Layout

  • src/protocol — pure, synchronous, allocation-friendly codec for the MQTT wire format. No networking or async dependencies, so it is unit-tested byte-for-byte and reused as-is by mqtt-broker.
    • varint — MQTT variable byte integer encoding.
    • packet — the top-level Packet enum, fixed header, and remaining-length framing/dispatch.
    • connect, publish, subscribe, ack — per-packet-type bodies.
    • properties — MQTT 5.0 properties (user properties, content type, message expiry, etc.); a no-op on MQTT 3.1.1 connections.
  • src/client/ — split by responsibility: types.rs (public data types), inner.rs (live-connection state + pending-ack/QoS-2 bookkeeping), io.rs (read loop, keep-alive loop, wire encode/write), tls.rs (TLS transport via rustls/tokio-rustls, type-erased behind a Transport trait so the rest of the client doesn't care whether it's plain TCP or TLS), mod.rs (the public MqttClient API: connect/publish/subscribe/unsubscribe/disconnect — including opt-in auto-reconnect and QoS 1/2 redelivery).
  • src/error.rs — MqttError / MqttResult.

Rust usage

use mqtt_client::{ConnectOptions, MqttClient, MqttVersion, QoS};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let mut opts = ConnectOptions::new("localhost", 1883, "demo-client", MqttVersion::V5);
    opts.keep_alive_secs = 30;

    let client = MqttClient::new(opts);
    let result = client.connect().await?;
    println!("connected, session_present={}", result.session_present);

    client.subscribe("stem/demo".into(), QoS::AtLeastOnce).await?;
    client
        .publish("stem/demo".into(), b"hello".to_vec(), QoS::AtLeastOnce, false)
        .await?;

    client.disconnect().await?;
    Ok(())
}

Register an MqttMessageListener (before or after connect()) to receive incoming PUBLISH messages and disconnect notifications without polling:

# use mqtt_client::{MqttMessage, MqttMessageListener};
struct Printer;
impl MqttMessageListener for Printer {
    fn on_message(&self, message: MqttMessage) {
        println!("{}: {:?}", message.topic, message.payload);
    }
    fn on_disconnected(&self, reason: String) {
        eprintln!("disconnected: {reason}");
    }
}

Robustness

  • Never blocks forever: every request has an operation timeout; QoS 1/2 steps are retransmitted (DUP=1) up to 3 times; when the connection drops, in-flight requests fail immediately.
  • Half-open connections are detected: no data from the broker for 1.5× the keep-alive interval declares the connection dead (reported once via on_disconnected).
  • Packet-size limit: ConnectOptions::max_packet_size rejects an oversized packet from its header.
  • Input validation: wildcard/empty topics and malformed filters are rejected locally with MqttError::Protocol before touching the wire; MQTT 5 failure reason codes on PUBACK/PUBREC/PUBCOMP surface as MqttError::Session.
  • No credential leaks: Debug output redacts passwords and private keys.
  • Listener safety: a panic/exception in your MqttMessageListener is contained and can't kill the connection's read loop.

Pull-style delivery and enhanced authentication

  • Pull-style: for runtimes that can't receive callbacks (Dart, Haskell), enable_message_queue(capacity) then next_message(timeout_ms) returns the next incoming message or None on timeout; last_disconnect_reason() is the polling twin of on_disconnected. It can be combined with a listener.
  • Enhanced authentication (MQTT 5): set ConnectOptions::auth_method (and optionally auth_data) and register an MqttAuthHandler with set_auth_handler; its respond(method, challenge) answers each broker challenge (returning None aborts). Requires MqttVersion::V5.

Foreign-language bindings

cargo rustc --release -p stem-mqtt-client --lib --crate-type cdylib
cargo run -p stem-mqtt-client --features uniffi/cli --bin uniffi-bindgen -- \
    generate --library ../../target/release/libmqtt_client.so \
    --language kotlin --out-dir bindings/kotlin

Or use the repo-level helper, which builds the right cdylib for your platform first: nu ../../scripts/generate_bindings.nu kotlin.

Examples

cargo run -p stem-mqtt-client --example pub_sub               # connect, subscribe, publish, receive
cargo run -p stem-mqtt-client --example will_and_retain        # Last-Will-and-Testament + retained messages
cargo run -p stem-mqtt-client --example shared_subscriptions   # $share/<group>/... round-robin work queue
cargo run -p stem-mqtt-client --example auth_client            # pairs with `stem-mqtt-broker --example auth_broker`
cargo run -p stem-mqtt-client --example mqtt_versions          # MQTT 3.1.1 + 5.0 on the same broker
cargo run -p stem-mqtt-client --example topics                 # topic hierarchies, `+`/`#` wildcards
cargo run -p stem-mqtt-client --example long_lived_connection  # persistent connection, keep-alive over ~20s

All expect a broker listening on 127.0.0.1:1883 (run cargo run -p stem-mqtt-broker --bin mqtt-broker first, or cargo run -p stem-mqtt-broker --example simple_broker).

Testing

cargo test -p stem-mqtt-client

Protocol round-trip tests live alongside each codec module (#[cfg(test)]). tests/redelivery.rs covers client-side QoS 1/2 redelivery and the keep-alive timing fix, against a minimal fake TCP peer (needed since the real broker always acks correctly/promptly, and tokio::time::interval's immediate first tick can't be observed against a real broker either) — everything else connection-level (the QoS 1/2 handshakes, Last-Will delivery, session resumption) is covered by mqtt-broker's integration tests, which drive a real client against a real broker over a loopback socket.

Metadata

Release files for stem-mqtt-client 0.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for stem-mqtt-client 0.4.1
File Interpreter ABI Platform Actions
stem_mqtt_client-0.4.1-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details for stem_mqtt_client-0.4.1-py3-none-win_amd64.whl
stem_mqtt_client-0.4.1-py3-none-manylinux_2_34_x86_64.whl Python 3 none Linux glibc 2.34+ x86-64 Details for stem_mqtt_client-0.4.1-py3-none-manylinux_2_34_x86_64.whl
stem_mqtt_client-0.4.1-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details for stem_mqtt_client-0.4.1-py3-none-macosx_11_0_arm64.whl

Total release size: 3.7 MB

Release files / stem_mqtt_client-0.4.1-py3-none-win_amd64.whl

Download URL stem_mqtt_client-0.4.1-py3-none-win_amd64.whl
Size 1.2 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
5d29bb89c7442d9cfa4e4cb5ae0fa0d0031369de8e8d7f796e51b57ab4c356c0
BLAKE2b-256 checksum
How to use checksums
77ae13a3237296e5a987e7401646b155ad67368674290f01be1fa8b3370c6dca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

Release files / stem_mqtt_client-0.4.1-py3-none-manylinux_2_34_x86_64.whl

Download URL stem_mqtt_client-0.4.1-py3-none-manylinux_2_34_x86_64.whl
Size 1.3 MB
Tags Linux glibc 2.34+ x86-64 Python 3
SHA-256 checksum
How to use checksums
2a73de4ae99ac1ba69e7a81f1b453e4fb43a193c9034dbeb953baaf417837b1a
BLAKE2b-256 checksum
How to use checksums
5b4374e1b849c49307692de716d9ab7d6166b13e5070e31eca31689c78eec800
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

Release files / stem_mqtt_client-0.4.1-py3-none-macosx_11_0_arm64.whl

Download URL stem_mqtt_client-0.4.1-py3-none-macosx_11_0_arm64.whl
Size 1.2 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
34b89b55415f8f8cee907e517690759fbd2c6be07cbec8292612024d4cc7dfac
BLAKE2b-256 checksum
How to use checksums
d2a9bcd87bb574531128c278a87d352c643f5e0f87e5846d1e7a360216c270d8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

Security for stem-mqtt-client 0.4.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 3 files in this release have been uploaded with provenance metadata.

Select from 3 files

Attestation for stem_mqtt_client-0.4.1-py3-none-win_amd64.whl

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.4.1 This release

3 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page