Skip to main content

zmqtt

PyPI version PyPI Downloads Tests License

Pure asyncio MQTT 3.1.1 and 5.0 for Python 3.10+, with deterministic subscription routing, bounded queues, and correlation-safe request/response.

Documentation · PyPI · Changelog

Why zmqtt?

  • Application-facing subscriptions. Each Subscription owns its filters, bounded queue, acknowledgement policy, and async iterator.
  • Deterministic routing. Wildcards, shared subscriptions, broker decorator prefixes, and MQTT 5 subscription identifiers are handled by the built-in router. One incoming PUBLISH is delivered once to the selected subscription.
  • High-level QoS. Packet identifiers and the QoS 1/2 protocol handshakes are managed by the client. Manual acknowledgement is opt-in per subscription.
  • Safe MQTT 5 request/response. Concurrent requests are matched by both response topic and correlation data and delivered exclusively to one pending request.
  • Bounded by default. Subscription queues and pending request futures apply backpressure instead of growing without limit.
  • Self-contained MQTT stack. The packet codec and protocol engine live in zmqtt; there is no Paho or other MQTT client dependency.
  • One API for MQTT 3.1.1 and 5.0. create_client() returns a version-typed client, so a type checker can reject MQTT 5-only calls on a 3.1.1 connection.

zmqtt and aiomqtt 3

aiomqtt 3 is no longer a Paho wrapper. It is also pure asyncio, fully typed, and has MQTT 5 flow control and opt-in automatic reconnection, but its API deliberately exposes more low-level MQTT 5 mechanics. zmqtt provides a higher-level application API and supports both current protocol versions.

zmqtt aiomqtt 3
MQTT versions 3.1.1 and 5.0 5.0 only
Receive model Subscription-local queues and iterators Client-wide messages() stream
Message routing Built in: wildcards, shared/decorated filters, subscription identifiers Left to the application
QoS 1/2 publish Publish packet IDs and the complete handshake are managed by publish() Caller supplies publish packet IDs and completes QoS 2 with pubrel()
Reconnection Enabled by default; active Subscription objects are restored Opt-in; no automatic resubscription—requires a persistent broker session or application-managed recovery
Request/response request() with correlation routing, cleanup, and backpressure MQTT properties exposed; correlation and response routing left to the application
MQTT protocol dependency Built-in codec and state machines External mqtt5 package

The comparison targets the aiomqtt 3.0 alpha API, where application code supplies packet identifiers for QoS 1/2 publishes, drives the remaining QoS 2 steps, and implements message routing and response correlation. zmqtt keeps the decisions applications need explicit — QoS, acknowledgement timing, MQTT 5 properties, subscription lifecycle, and reconnect policy — while handling that protocol machinery in the client. The result is less application code, fewer protocol edge cases, and one typed API for both MQTT 3.1.1 and 5.0.

Installation

pip install zmqtt

Quick start

import asyncio

from zmqtt import QoS, create_client


async def main() -> None:
    async with create_client("localhost") as client:
        async with client.subscribe(
            "sensors/#",
            qos=QoS.AT_LEAST_ONCE,
        ) as messages:
            await client.publish(
                "sensors/temperature",
                "23.5",
                qos=QoS.AT_LEAST_ONCE,
            )
            msg = await messages.get_message()
            print(msg.topic, msg.payload.decode())


asyncio.run(main())

create_client() defaults to MQTT 3.1.1. Pass version="5.0" for the MQTT 5 API.

Publish

from zmqtt import QoS

await client.publish("events/online", b"device-42")
await client.publish(
    "commands/restart",
    b"device-42",
    qos=QoS.AT_LEAST_ONCE,
    retain=False,
)

Payloads may be bytes or str; strings are encoded as UTF-8. QoS 1 waits for PUBACK. QoS 2 completes the PUBREC/PUBREL/PUBCOMP handshake before returning.

Subscribe and route

async with client.subscribe(
    "sensors/+/temperature",
    "sensors/#",
    receive_buffer_size=100,
) as messages:
    async for msg in messages:
        print(msg.topic, msg.payload)

If one PUBLISH matches multiple filters in the same subscription, zmqtt selects the most specific filter (literal before + before #) and enqueues the message once. MQTT 5 subscription identifiers are used when the broker supplies them, which disambiguates overlapping subscriptions reliably.

Shared subscriptions and broker decorator prefixes work with the same API:

async with client.subscribe("$share/workers/jobs/#") as jobs:
    async for job in jobs:
        await process(job)

The public topic_matches() helper follows the same matching rules, including $share, $queue, $exclusive, and configured stripped prefixes.

Manual acknowledgement

Manual acknowledgement only has an effect at QoS 1 or 2:

from zmqtt import QoS, create_client

client = create_client(
    "localhost",
    client_id="orders-worker-1",
    clean_session=False,
)

async with client:
    async with client.subscribe(
        "orders/#",
        qos=QoS.AT_LEAST_ONCE,
        auto_ack=False,
    ) as messages:
        async for msg in messages:
            await save_to_database(msg)
            await msg.ack()

A stable client ID and persistent broker session make an unacknowledged message eligible for redelivery after reconnect. They do not make application processing exactly once, so handlers should still be idempotent. MQTT 5 clients also need a positive session_expiry_interval for a session to survive disconnection.

MQTT 5 request/response

from zmqtt import create_client

async with create_client("localhost", version="5.0") as client:
    reply = await client.request(
        "services/echo",
        b"hello",
        timeout=5.0,
    )
    print(reply.payload)

zmqtt subscribes to the response topic before publishing, generates a response topic and correlation data when omitted, and matches the reply by the exact (response_topic, correlation_data) pair. Concurrent requests may share a response topic. A matching reply is delivered only to its pending request(); it is not also enqueued for an ordinary subscription. Unmatched or late replies fall through to normal routing, which selects at most one subscription. The request dispatcher itself does not retain them.

The responder must copy the request's correlation data unchanged:

from zmqtt import PublishProperties

async with client.subscribe("services/echo") as requests:
    async for request in requests:
        assert request.properties is not None
        assert request.properties.response_topic is not None
        assert request.properties.correlation_data is not None
        await client.publish(
            request.properties.response_topic,
            request.payload,
            properties=PublishProperties(
                correlation_data=request.properties.correlation_data,
            ),
        )

The timeout argument bounds the reply wait after the response subscription is ready and the request has been published. Use asyncio.wait_for() around the whole coroutine when setup and publishing must be included in the cancellation budget; cancellation cleanup can still extend the wall-clock completion time.

Reconnection

Automatic reconnection is enabled by default. Active subscriptions are re-registered after a successful reconnect while their application queues stay alive. The default policy makes at most five connection attempts:

from zmqtt import ReconnectConfig, create_client

client = create_client(
    "localhost",
    reconnect=ReconnectConfig(max_attempts=None),  # retry indefinitely
)

Broker refusals such as invalid credentials are not retried. See Reconnection for the complete failure semantics.

MQTT 5 properties

from zmqtt import PublishProperties, create_client

async with create_client("localhost", version="5.0") as client:
    await client.publish(
        "events/reading",
        b'{"value": 42}',
        properties=PublishProperties(
            content_type="application/json",
            message_expiry_interval=300,
            user_properties=(("source", "sensor-01"),),
        ),
    )

MQTT 5 also adds session expiry, subscription identifiers, no_local, retain handling, publish properties, and a low-level AUTH packet API.

Learn more

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zmqtt-0.1.1.tar.gz (38.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zmqtt-0.1.1-py3-none-any.whl (49.6 kB view details)

Uploaded Python 3

File details

Details for the file zmqtt-0.1.1.tar.gz.

File metadata

  • Download URL: zmqtt-0.1.1.tar.gz
  • Upload date:
  • Size: 38.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for zmqtt-0.1.1.tar.gz
Algorithm Hash digest
SHA256 aeb8bda249b2104b90dcf3baa274e8e8357077e2a94f67fe0a58e973d1cc614b
MD5 b6471e82b28c4d6feccb36653abba0c1
BLAKE2b-256 b48f87efb99d768ccbf4728b3e80d86c0a89fefbfc698fc0e7348133fc7272c3

See more details on using hashes here.

Provenance

The following attestation bundles were made for zmqtt-0.1.1.tar.gz:

Publisher: release.yaml on faststream-community/zMQTT

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file zmqtt-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: zmqtt-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 49.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for zmqtt-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 935799127bee384a05c77f9fe83e43e8c291c8ceea02eac9a5413756d84ef0c1
MD5 139d6f49682bf2eebd15bd9e7e9948d1
BLAKE2b-256 c57c6c046cf69bbc265f2b622c3a55bfac6abe2f142a858c0c086a1c53414192

See more details on using hashes here.

Provenance

The following attestation bundles were made for zmqtt-0.1.1-py3-none-any.whl:

Publisher: release.yaml on faststream-community/zMQTT

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

This release

0.1.1 This release

2 files

0.1.0

2 files

0.0.6

2 files

0.0.5

2 files

0.0.4

2 files

0.0.3

2 files

0.0.2

2 files

0.0.1

2 files

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