Library / SDK
njh/ruby-mqtt avatar
njh/ruby-mqtt

ruby-mqtt: a pure Ruby MQTT client, plus the packet layer underneath

Pure Ruby gem that implements the MQTT protocol, a lightweight protocol for publish/subscribe messaging.

560 stars141 forksRubyMIT

At a glance

What is it?
ruby-mqtt is a Ruby gem that implements the MQTT protocol with no native extension, offering a Client class for publish and subscribe plus a separate lower level API for parsing and generating MQTT and MQTT-SN packets. It is MIT licensed, and the README states plainly that QoS 2, automatic reconnection and local persistence are not supported.
Who is it for?
Adopt ruby-mqtt if you want an MQTT client with no native extension in a Ruby service, or you need to build a client or broker on top of its packet parsing and serialising layer. Skip it if your deployment needs QoS 2, automatic reconnection or persistence across a restart, since the README lists all three as unsupported.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 168 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

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

Editorial analysis

Two layers in one gem, and the second one is the interesting part

ruby-mqtt is described as a pure Ruby gem that implements the MQTT protocol, a lightweight protocol for publish and subscribe messaging, and it also includes a class for parsing and generating MQTT-SN packets. That last sentence points at the most useful thing in the repository, because the parsing and serialising of MQTT and MQTT-SN packets is a separate lower-level API, and the README says you can use it to build your own clients and servers without using any of the rest of the code in the gem. That is the difference between an MQTT client and an MQTT toolkit, and it is the reason a gem with a narrow surface area is worth having. A team that needs to speak MQTT over a transport the common clients do not cover, a sensor gateway on a constrained link, a test harness that asserts on the exact bytes on the wire, or a broker written in Ruby, can use the packet layer without adopting the Client class at all. The gem is MIT licensed, the API documentation is on rubydoc, and the resources section links the protocol specifications for MQTT v3.1.1, MQTT v3.1 and MQTT-SN v1.2, which tells you the target versions are the 3.x line rather than the newer 5.0 release.

Connecting, and the TLS default that catches people out

The library overview starts with connecting, and the API is flexible about how you say it. A new client connection can be created by passing either an MQTT URI, a host and port, or a hash of attributes.

~~~ ruby client = MQTT::Client.connect('mqtt://myserver.example.com') client = MQTT::Client.connect('mqtts://user:[email protected]') client = MQTT::Client.connect('myserver.example.com') client = MQTT::Client.connect('myserver.example.com', 18830) client = MQTT::Client.connect(:host => 'myserver.example.com', :port => 1883 ... ) ~~~

The TLS detail is the one to notice, because the default is not the safe one. TLS and SSL is not enabled by default, and to enable it you pass the ssl option as true.

~~~ ruby client = MQTT::Client.connect( :host => 'test.mosquitto.org', :port => 8883, :ssl => true ) ~~~

That is a deliberate choice rather than an oversight, since the gem predates the point where insecure defaults became a complaint, and it means a reader of the quick start, which connects to a public broker over plain TCP, is not told to expect encryption. The alternative to the connect method is to build a Client and set attributes, which is what you need for client certificate authentication, where you set the host, enable ssl and point at the certificate, key and CA files before connecting. The connect timeout defaults to 30 seconds when opening a TCP socket and can be set with connect_timeout.

Publish, subscribe, and a get that blocks

The three verbs a broker client needs are covered plainly. Publishing takes a topic, a payload and an optional retain flag, and the method will return once the message has been sent to the MQTT server.

~~~ ruby client.publish(topic, payload, retain=false) ~~~

Subscribing takes one or more topic filters, and the examples show a single topic, two topics and a wildcard form.

~~~ ruby client.subscribe( 'topic1' ) client.subscribe( 'topic1', 'topic2' ) client.subscribe( 'foo/#' ) ~~~

Receiving is where the shape of the API bites. The get method will block until a message is available, and it returns the topic, which is the name of the topic the message was sent to, and the message, which is a string.

~~~ ruby topic,message = client.get ~~~

Alternatively you can give the get method a block, which will be called for every message received and loop forever.

~~~ ruby client.get do |topic,message| # Block is executed for every message received end ~~~

The blocking behaviour is the practical difference between the two forms. A bare get is a synchronous pull that parks the thread until something arrives, which is right for a simple consumer loop and wrong for a service that has other work to do on the same thread, and the block form is the same operation with the loop built in. The quick start shows the block form in a connect block, and the whole connect call also has two shapes, with or without a block, and when a block is given the disconnection at the end of the block is implicit.

The packet API writes bytes to an IO handle

The low-level example in the README is short and shows the style of the packet API, which is object construction and IO rather than a client. Parsing a string containing a binary packet into an object, then writing a PUBACK packet to an IO handle, and then writing an MQTT-SN Publish packet with QoS -1 to a UDP socket.

~~~ ruby # Parse a string containing a binary packet into an object packet_obj = MQTT::Packet.parse(binary_packet) # Write a PUBACK packet to an IO handle ios << MQTT::Packet::Puback(:id => 20) # Write an MQTT-SN Publish packet with QoS -1 to a UDP socket socket = UDPSocket.new socket.connect('localhost', MQTT::SN::DEFAULT_PORT) socket << MQTT::SN::Packet::Publish.new( :topic_id => 'TT', :topic_id_type => :short, :data => "The time is: #{Time.now}", :qos => -1 ) socket.close ~~~

Two things are visible in that snippet. The parse method takes binary data and returns an object, and the packet classes are constructed with keyword arguments and then written to an IO with the shift operator, so the same code path serves a TCP socket, a UDP socket or a StringIO in a test. The MQTT-SN example uses a topic id of TT with the type set to short, which is the identifier-based addressing that MQTT-SN uses instead of topic names, and a QoS of -1, which in MQTT-SN is the fire and forget delivery mode. The default port for the SN variant comes from the library as MQTT::SN::DEFAULT_PORT, so you do not have to know the number. The examples directory in the repository carries the runnable versions of these, including authentication.rb, client_cert.rb, environment_uri.rb, get_packets.rb, mqttsn_publish_minus_one.rb, readonly_proxy.rb, simple_get.rb and simple_publish.rb.

The three limitations decide whether this fits your broker

The limitations section is the part to read before choosing the gem, and it lists three things plainly. QoS 2 is not currently supported by the client. Automatic re-connects to the server are not supported. There is no local persistence for packets. Each of those is a real constraint and each maps to a class of use. QoS 2 is the exactly-once delivery mode, where the broker and client exchange acknowledgements to guarantee a message is delivered exactly once, and its absence means the gem offers at-most-once and at-least-once only, which is fine for a sensor feed and wrong for a command channel where a duplicated command is a problem. The absence of automatic reconnection means the reconnect logic is yours, and since MQTT connections drop for all the usual reasons, a production consumer has to implement a backoff loop, and the absence of local persistence means a message that is in flight when the process dies is gone, so a consumer that must not lose messages needs a durable broker and a client-side queue of its own. None of these is unusual for a small client library, but all three are the kind of thing that surfaces at three in the morning rather than in a design review. The release history gives a hint about the maintenance picture, with v0.7.0 from 2025-10-29, v0.6.0 from 2023-02-17 and v0.5.0 from 2017-05-26, and the last push to the repository on 2026-05-08, so the gem is still touched but moves rarely.

Editorial conclusion

Adopt ruby-mqtt if you want an MQTT client with no native extension in a Ruby service, or you need to build a client or broker on top of its packet parsing and serialising layer. Skip it if your deployment needs QoS 2, automatic reconnection or persistence across a restart, since the README lists all three as unsupported. Verify first which broker protocol version you need, whether the broker expects MQTT-SN over UDP rather than MQTT over TCP, and that your Ruby version is compatible with the gem before you build a service on top of it.

Frequently asked questions

What does the ruby-mqtt gem provide?

It is a pure Ruby implementation of the MQTT protocol for publish and subscribe messaging, and it also includes a class for parsing and generating MQTT-SN packets. The parsing and serialising of MQTT and MQTT-SN packets is a separate lower level API, which you can use to build your own clients and servers without using the rest of the gem.

How do I connect with TLS and client certificates in ruby-mqtt?

TLS is not enabled by default, so you pass the ssl option as true along with the host and port. For client certificate authentication, create a Client, set the host, enable ssl, and assign cert_file, key_file and ca_file before calling connect. The default connect timeout is 30 seconds and can be changed with connect_timeout.

What are the limitations of the ruby-mqtt gem?

The README lists three: QoS 2 is not currently supported by the client, automatic re-connects to the server are not supported, and there is no local persistence for packets. The gem is MIT licensed and available on Rubygems as mqtt, with a GitHub source snapshot usable through Bundler.

Official sources

  1. License: MIT
  2. njh/ruby-mqtt on GitHub
  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/njh-ruby-mqtt.svg)](https://hysenlabs.com/projects/njh-ruby-mqtt)

Was this useful?