# mqtt_client: an MQTT client for Dart that hides the protocol work

> mqtt_client is a Dart implementation of MQTT v3, with a server build that speaks TCP and WebSockets and a browser build that speaks WebSockets. It handles the connection handshake, the message exchanges for the three QoS levels and the keep alive mechanism, leaving you to publish and subscribe. It began as a port of the C# nMQTT library and now ships an MQTT v5 client in a separate package.

**shamblett/mqtt_client** — A server and browser based MQTT client for dart

- Repository: https://github.com/shamblett/mqtt_client
- Stars: 584 · Forks: 192
- Language: Dart
- License: NOASSERTION
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/shamblett-mqtt-client

## The protocol work is the point of the library

mqtt_client is a server and browser based MQTT client for Dart. The client is an MQTT v3 implementation, covering both 3.1 and 3.1.1, and it supports subscription and publishing at all QoS levels, keep alive and synchronous connection.

The README is clear about the design intent. The client is designed to take as much MQTT protocol work off the user as possible: the connection protocol is handled automatically, as are the message exchanges needed to support the different QoS levels and the keep alive mechanism. The result is that you concentrate on publishing and subscribing rather than on MQTT itself.

That is a larger claim than it sounds, because the parts of MQTT that are tedious are exactly the parts a protocol library hides. The CONNECT exchange and its acknowledgement, the four packet types involved in QoS 1 delivery and the two in QoS 2, the PINGREQ and PINGRESP pair that keeps the connection alive, and the DISCONNECT handshake. A hand written client gets each of these almost right.

There is an MQTT v5 client, but it is not in this package. The README links an equivalent MQTT v5 client published separately as mqtt5_client, so if version 5 of the protocol is what you need, that is the package to look at, and this one is the v3 line.

The code has a pedigree worth knowing about. The README says the code is originally a port from the C# nMQTT client library to Dart, which is the kind of provenance that predicts the API shape, and it is also a good sign, since a port means the protocol behaviour was already battle tested in another language.

## Two builds, because a browser cannot open a socket

The client ships in two forms, and the difference between them is a constraint of the platform rather than a design preference.

The server client supports both normal and secure TCP connections, and secure (wss) and non-secure (ws) WebSocket connections. The browser client supports only the WebSocket variants, secure and non-secure.

The reason is the browser sandbox. A page cannot open a raw TCP socket, so a browser can only reach an MQTT broker over WebSockets, which means the broker has to be fronted by a WebSocket endpoint. If you are writing a Flutter desktop or server side service, you have the whole protocol available. If you are writing a Flutter web application, the broker needs to speak WebSockets.

The example directory makes the split visible, with separate files for the two worlds. mqtt_client_universal.dart, mqtt_server_client.dart, mqtt_server_client_secure.dart, mqtt_server_client_websocket.dart and mqtt_server_client_websocket_secure.dart cover the server side variants, while mqtt_browser_client.dart covers the browser build.

The universal example is the interesting one to read first, because it is the case where the same code has to work against different brokers and different transports, and it is where the configuration differences between a desktop app and a web app become visible.

## QoS 0 to 2, and an acknowledgement you can take over

The example set covers the delivery levels in a way that says a lot about how much control the library keeps.

There is a straightforward QoS 1 publish, and then there is a separate example named for publishing at QoS 1 with manual acknowledgement. The presence of that second file is the interesting part. In normal operation the library acknowledges receipt for you, because that is what taking the protocol work off the user means. But there are cases where the acknowledgement is a decision rather than a reflex, for example when the delivery of a message to your application depends on something else succeeding first, and the library lets you take the acknowledgement over.

There is a QoS 2 publish example as well, which is the level with a four-packet handshake and therefore the one most likely to expose a client library's state handling. QoS 2 promises exactly one delivery, and a client that gets the retransmission rules wrong will show duplicate or missing messages under packet loss, which is exactly the kind of bug that is invisible on a quiet network.

The topic side has two examples, one for a wildcard subscription and one for a wildcard with filtering, so the matching rules are demonstrated rather than described.

The learning value of the example directory is high for a protocol client, and the README says so: examples of usage can be found there, and the test directory contains standalone runnable scripts demonstrating subscription, publishing and topic filtering.

## Keep alive, dropped connections and auto reconnect

The four examples about connection failure are the ones that separate a client library from a toy.

There is an example for a failed connection, which is the case where the broker refuses or the network is unreachable. There is an example for keep alive disconnect, where the connection is dropped because the keep alive mechanism noticed the peer had gone away rather than because the socket closed. And there is an example for a keep alive disconnect with auto reconnect, which is the case that matters in the field: the connection died while the process was running, and the client brought it back.

A third example, mqtt_server_client_autoreconnect.dart, covers reconnection in the general case.

This matters because the MQTT keep alive mechanism is a timer on both ends. The client sends PINGREQ at an interval, the broker answers with PINGRESP, and if either side stops hearing from the other for one and a half intervals the connection is considered dead and is closed. A client that has not implemented the timer properly will keep a connection that the broker has already discarded, and the first symptom is a publish that appears to succeed and is never delivered.

So the example set doubles as the failure mode catalogue for the library, and the auto reconnect example is the one to read if you are deploying this on a device that moves between networks.

## Cloud provider targets and a Google IoT Core example

The README lists the platforms the client has been used with, and the list is a good proxy for what the transport layer has to survive.

The client has been used successfully with the MQTT brokers from several major cloud provider IoT and MQTT platforms: Google IoT Core, Amazon AWS, Microsoft Azure and IBM. It has also been used with a range of publicly available brokers such as Mosquitto and with proprietary ones.

What that implies in practice is that the client has been exercised against broker authentication schemes that differ in their details, and the examples show it. There is a google_iot_core.dart example that demonstrates how to use secure connections and switch MQTT protocols, and there are two AWS examples, aws_iot_certificates.dart and aws_iot_cognito_amplify.dart, which point at the two common ways of getting a credential: a client certificate and the Cognito identity flow.

There is also an example for the Adafruit MQTT broker in a Flutter project, linked from the README, which is a useful pointer for anyone working with a hosted broker rather than an enterprise one.

The README also points out that the changelog carries the details for specific versions, which is where you should look before an upgrade, since a protocol client that changes its default behaviour is the kind of change that shows up as a delivery anomaly rather than an error.

## Mobile permissions, and the Bonjour service name that matters

Using the client from a Flutter application on Android or iOS needs platform configuration, and the README spells out exactly what to add.

On iOS, the keys go into the Info.plist file at ios/Runner/Info.plist:

```
<key>NSLocalNetworkUsageDescription</key>
<string>Looking for local tcp Bonjour service</string>
<key>NSBonjourServices</key>
<array>
  <string>mqtt.tcp</string>
</array>
```

The Bonjour service name is the detail to get right. The entry has to be the service type the broker advertises, and mqtt.tcp is the one MQTT uses. A mismatch here does not produce an error, it produces a discovery that silently finds nothing.

On Android, the permissions go into the AndroidManifest.xml file at android/app/src/main/AndroidManifest.xml:

```
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
```

The local network description string is what iOS shows in the permission prompt, so the wording matters for the review of an application that ships in the App Store.

These two blocks are short, and they are the whole of the mobile setup. They are also the part most likely to be missed, because on a desktop machine the client simply works and the problem only appears on a phone.

## A published software bill of materials and a custom licence

The repository contains a couple of files that are worth a look before you depend on the package.

There are two software bill of materials files, sbom.spdx and sbom.yaml, checked in at the root. An SBOM committed to the repository is a supply chain practice that more projects should copy: it is a machine readable inventory of what is in the dependency tree, which lets an organisation answer a vulnerability question about a transitive dependency without rebuilding the tree by hand. The FOSSA badge in the README points at the same service for licence analysis.

The licence, though, is the one to read. GitHub records it as a custom licence that it cannot classify, and the LICENSE file at the root is the authoritative text. The README does not summarise it, so if you are going to ship the client in a product, that file is where the answer is.

The rest of the tree is conventional for a Dart package: lib/ for the code, example/ with more than twenty runnable examples including a pem/ directory and a screenshots/ directory, test/ for the test suite, pubspec.yaml, an analysis_options.yaml for the analyzer, AUTHORS.md, a CHANGELOG.md and a .github/ directory with a CI workflow named ci.yml.

There are no GitHub releases, so the version lives in pubspec.yaml and the changelog is the record of what changed. The last push to the repository was on 2026-10-15, so the work is recent even though there is no tagged release history to browse.

## Conclusion

mqtt_client suits a Dart or Flutter team that needs an MQTT client without writing the handshake, the QoS acknowledgement dance and the keep alive timer by hand, and it suits browser applications that need a WebSocket-only client. It does not suit you if you need MQTT v5 in the same package, because the v5 implementation lives separately in mqtt5_client, and it does not suit a project that needs a broker rather than a client. Check three things before you adopt it: which QoS levels and acknowledgement style you need, since the manual acknowledgement example shows the library will hand that control to you when you want it, whether your broker is reachable with plain WebSockets if you are targeting the browser build, and that you have added the iOS local network and Bonjour entries or the Android permissions, because without them a mobile device cannot discover a local broker. The last push to the repository was on 2026-10-15 and the project publishes no GitHub releases.

## FAQ

### Which MQTT versions does mqtt_client support?

The package implements MQTT v3, covering 3.1 and 3.1.1, with subscription and publishing at all QoS levels plus keep alive and synchronous connection. An equivalent MQTT v5 client is published separately as the mqtt5_client package.

### What is the difference between the server client and the browser client?

The server client supports normal and secure TCP connections as well as secure and non-secure WebSocket connections. The browser client supports only the WebSocket variants, secure and non-secure, because a browser cannot open a raw TCP socket.

### Can I acknowledge QoS 1 messages myself?

Yes. The example set includes a publish at QoS 1 with manual acknowledgement alongside the ordinary QoS 1 publish, so the library will leave the acknowledgement to your code when you need to decide it yourself.

### What platform permissions does a Flutter app need?

On iOS, add NSLocalNetworkUsageDescription and an NSBonjourServices array containing mqtt.tcp to the Info.plist. On Android, add the INTERNET and ACCESS_NETWORK_STATE permissions to the AndroidManifest.xml.

### Which brokers has mqtt_client been used with?

The README lists Google IoT Core, Amazon AWS, Microsoft Azure and IBM among the cloud provider platforms, along with public brokers such as Mosquitto and proprietary ones. The examples include Google IoT Core with secure connections and AWS certificate and Cognito based flows.

## Sources

- [Issues](https://github.com/shamblett/mqtt_client/issues)
- [README](https://github.com/shamblett/mqtt_client/blob/master/README.md)
- [shamblett/mqtt_client on GitHub](https://github.com/shamblett/mqtt_client)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/shamblett-mqtt-client
