The Ultimate Guide on How to Use MQTT with Node.js
Written by Peter Giacomo Lombardo
Category: HiveMQ MQTT IoT Node.js
Published: May 16, 2023
Node.js is a popular server-side platform for building scalable and robust web applications. With the continued popularity and growth of MQTT in many use cases, it’s already well-established in the Node.js ecosystem.
MQTT (Message Queue Telemetry Transport) is a lightweight protocol for exchanging data between devices over a network. It uses the publish <–> consumer model, particularly the HiveMQ MQTT broker, which can scale up to 200 million connections!
In this article, we will explore how to use MQTT with Node.js, covering topics, such as subscribing to a topic, publishing an MQTT message, QoS levels, error handling, etc. The article also covers advanced use cases and touches on related topics such as payload management.
Before diving into the details, let’s first understand MQTT and how it works.
For Neophytes – Introduction to MQTT and Node.js
Thanks to its lightweight and event-driven architecture, Node.js can also run on resource-constrained devices making it a popular choice for building IoT applications. Additionally, Node.js has several libraries and tools specifically designed for building IoT applications, such as the Johnny Five framework and Node-RED - a visual programming tool.
Because of these strengths, Node.js is a popular choice for companies such as Netflix, Bosch, Siemens, Honeywell, NASA and many more.
MQTT is a messaging protocol that allows devices to communicate with each other over a network. It was originally developed in 1999 by Andy Stanford-Clark of IBM and Arlen Nipper of Arcom Control Systems. However, the OASIS MQTT Technical Committee currently manages it, and is responsible for maintaining and evolving the MQTT specification.
MQTT is designed to be lightweight and efficient, making it an ideal choice for IoT (Internet of Things) devices. It uses a publish/subscribe model, where publishers send messages to a broker, which then distributes them to subscribers who have subscribed to the relevant topics.
With that done, let’s get to it.
MQTT Package Options in Node.js
A few popular MQTT client packages for Node.js provide a range of features and functionalities. Here are some of the most popular MQTT client packages:
MQTT.js: MQTT.js is a client library for the MQTT protocol that supportsNode.js and web browsers. It provides a simple API for connecting to an MQTT broker, subscribing to topics, and publishing messages. It is widely used and has a large and active community.
mqtt-async: mqtt-async is an async wrapper around the MQTT.js package. It allows you to use Promises that were introduced in ECMAScript 6 (ES6).
aedes-client: aedes-client is an MQTT client library for Node.js bundled with the Barebone Aedes MQTT broker. It supports most MQTT features. We won’t be covering this client in this article.
For the rest of this article, we will mainly focus on the MQTT.js package, but will also cover mqtt-async towards the end.
CommonJS Versus ES6
CommonJS modules are loaded synchronously and use the
require function to import modules. For example:
ES6 modules are loaded asynchronously and use the
import statement to import modules. For example:
The MQTT.js package supports both CommonJS and ES6 module systems. You can use either
The MQTT.js package supports both, but it’s good to know the differences and how they may affect your code. For the rest of this article, we will be using the ES6 syntax.
This section assumes you already have a functioning Node.js installation locally. If you don’t, check out https://nodejs.org/en to install Node.js.
Before we start working with MQTT.js, we need to install the MQTT package. We can do this using npm (Node Package Manager). Open your terminal and type the following command:
or alternatively via Yarn:
Browser CDN Support
The MQTT package is also available through unpkg here.
Further, the package has instructions on how to use the package with Browserify, React, and Webpack. See the Github page for these instructions.
Connecting to an MQTT broker
The MQTT protocol uses the concepts of clients (what we cover here in this article) and Brokers. An MQTT broker is a server that acts as an intermediary between MQTT clients.
For a more in-depth explanation of MQTT brokers and clients, see Introducing the MQTT Protocol - MQTT Essentials: Part 1.
For the rest of this article, we’ll use HiveMQ’s public broker to connect and perform operations.
To connect to an MQTT broker, we need to create an MQTT client instance. We can do this using the
mqtt package we just installed.
In the above example, we create an MQTT client instance and connect it to a broker with the address
Connect using Credentials
The MQTT.js package supports authentication when connecting to an MQTT broker.
You’ll need this if you are using HiveMQ cloud. You can generate and retrieve your credentials from your dashboard.
Here’s an example of how to connect with authentication:
We create an MQTT client instance above and connect to the HiveMQ broker with the address
mqtt://broker.hivemq.com. We also specify the
password options to authenticate the client with the broker.
Authentication such as this is often used to secure networks of clients and limit access to guarded data.
Connect with a client SSL Certificate
You can also connect to an MQTT broker with SSL/TLS encryption and client-side SSL/TLS authentication.
Here’s an example of how to connect to an MQTT broker with SSL certificates:
In this example, we specify the following options:
protocol:the protocol to use (
mqttsfor SSL/TLS encryption)
host:the hostname of the broker
port:the port number to connect to (usually
8883for SSL/TLS encryption)
ca:an array of trusted CA certificates
cert:the client certificate
key:the client private key
We are also using the
fs module to read the SSL certificates from the file system.
SSL/TLS encryption and client-side SSL/TLS authentication allow us to securely connect to an MQTT broker and protect our MQTT data from eavesdropping and tampering.
MQTT Extended Authentication
Extended authentication in MQTT version 5 provides additional authentication options beyond the standard username and password.
See this helpful video to learn more about MQTT 5 Enhanced Authentication:
One example of a typical extended authentication implementation is using certificates:
MQTT.js supports client-side SSL/TLS authentication, which can be used to authenticate clients with certificates. Here’s an example of using certificates for extended authentication:
In this example, we specify the client-side SSL/TLS certificates for authentication and listen for the
auth event of the MQTT client instance to perform the additional authentication logic in the event listener.
Extended authentication provides flexible and secure authentication options for MQTT applications, helping to prevent unauthorized access to MQTT data.
More information on MQTT authentication & even authorization is available:
- Authentication with Username and Password - MQTT Security Fundamentals
- Advanced Authentication Mechanisms - MQTT Security Fundamentals
- Authorization - MQTT Security Fundamentals
Connect over Websockets
Websockets are helpful partly because they can run over HTTP ports if needed. It’s a protocol for two-way communication between a client and a server over a single, long-lived, bi-directional TCP connection. Unlike traditional HTTP requests, which are unidirectional, a WebSocket connection enables real-time communication between the client and server, allowing instant updates and notifications.
MQTT can use Websockets as a transport, so we can connect using a Websocket.
Need to get past a firewall? Configure your client and broker to connect Websocket c over port 80 or 443.
To make a WebSocket connection using the MQTT.js library, specify the
ws protocol in the MQTT broker URL when creating the MQTT client instance.
Modern web browsers widely support WebSocket connections and are available as a standard feature in many programming languages and frameworks.
A Note on TCP Ports Used for MQTT
The two most commonly used ports for MQTT are 1883 and 8883.
Port 1883 is the default unencrypted port for MQTT and is usually used for communication over a local network or a secure network, such as a VPN.
Port 8883 is the default port for MQTT over SSL/TLS (Secure Sockets Layer/Transport Layer Security). It is used for communication over the internet or other untrusted networks where security is a concern.
The following table illustrates a few common default ports for various connect strategies. These ports can be configured to use different values depending on the specific MQTT implementation or use case. Check with your broker to be sure which ports are open for which functionality.
Note that TCP ports 8883 and 1883 are registered with IANA for MQTT TLS and non-TLS communication respectively.
|1883||TCP||Default unencrypted port for MQTT communication|
|8000||TCP||Port for MQTT over Unsecured WebSocket protocol|
|8080||TCP||Port for MQTT over WebSocket protocol|
|8883||TCP||Default port for MQTT over SSL/TLS encryption and auth|
|8884||TCP||Default port for MQTT over Websocket with SSL/TLS encryption|
Ports can vary from broker to broker, so check the documentation to see which ports your broker offers.
Arguments & Options
For a complete list and description of arguments & options for the connect operation, see the MQTT.js repository documentation.
Subscribing to an MQTT Topic
We can use the
subscribe method of the MQTT client instance to subscribe to an MQTT
This simply subscribes to the
Topics are key protagonists in MQTT. For more information on topics, see MQTT Topics, Wildcards, & Best Practices - MQTT Essentials: Part 5
Specifying a Message Handler
Making a subscription is great, but how do we execute code when receiving a message? Setup a handler:
Arguments & Options
|A string or array topic to subscribe to. It can also be an object, it has as object keys the topic name and as value the QoS, like |
|The options to subscribe with|
|QoS subscription level, default 0|
|No Local MQTT 5.0 flag (If the value is true, Application Messages MUST NOT be forwarded to a connection with a ClientID equal to the ClientID of the publishing connection)|
|Retain as Published MQTT 5.0 flag (If true, Application Messages forwarded using this subscription keep the RETAIN flag they were published with. If false, Application Messages forwarded using this subscription have the RETAIN flag set to 0.)|
|Retain Handling MQTT 5.0 (This option specifies whether retained messages are sent when the subscription is established.)|
|MQTT 5.0 properties object|
Publishing a message
To publish a message to an MQTT topic, we can use the
publish method of the MQTT client instance.
Here we publish a simple string to the
Using the Retain Flag
Setting the MQTT retain option to true means that the most recent message with the same topic will be stored on the broker and sent to new subscribers when they connect to the topic. This is useful for providing initial state or configuration data to new subscribers.
Here’s how to send an MQTT message and notify the MQTT broker to “retain” that message for all new subscribers:
With MQTT v5 you can send User Properties, similar to HTTP headers. User properties are optional key-value pairs that can be added to MQTT messages. They can be used to provide additional context or metadata about the message.
Arguments & Options Reference
This is the entire list of arguments & options for the publish operation.
|The topic to publish to, |
|The message to publish, |
|The options to publish with|
options can be:
|QoS level, |
|Retain flag, |
|Mark as duplicate flag, |
|MQTT 5.0 properties |
properties can be:
|Payload is UTF-8 Encoded Character Data or not |
|The lifetime of the Application Message in seconds, |
|Value that is used to identify the Topic instead of using the Topic Name, |
|String which is used as the Topic Name for a response message, |
|Used by the sender of the Request Message to identify which request the Response Message is for when it is received, |
|The User Property is allowed to appear multiple times to represent multiple name, value pairs, |
|Representing the identifier of the subscription, |
|String describing the content of the Application Message, |
Events in MQTT.js
The MQTT.js package provides several event callbacks to handle various events in an MQTT client’s lifecycle. Here are some of the most commonly used events in the MQTT.js package and what they are used for:
connectevent is emitted when the MQTT client successfully connects to the broker. This event can be used to perform actions that depend on the client being connected, such as subscribing to topics or publishing messages. A
connackobject representing the received CONNACK packet is passed to the event handler.
reconnectevent is emitted when the MQTT client tries to reconnect to the broker after a connection loss. This event can be used to perform actions that depend on the client being reconnected, such as resubscribing to topics or republishing messages.
disconnectevent in the MQTT.js package is emitted when the MQTT client disconnects from the broker for any reason, whether it’s due to an intentional disconnection initiated by the client or an unexpected disconnection due to network issues, broker unavailability, or other reasons.
endevent is emitted when
mqtt.Client#end()is called. If a callback was passed to
mqtt.Client#end(), this event is emitted once the callback returns.
packetsendevent is emitted each time the client sends any MQTT packet. The sent packet as packet will be passed to the handler.
packetreceiveevent is emitted each time the client receives any MQTT packet. The received packet as packet will be passed to the handler.
messageevent is emitted when the MQTT client receives a message from the broker. This event can be used to handle incoming messages and perform actions based on the content of the message, such as updating a user interface or triggering a process. The handler for this event will receive three arguments: topic: the topic of the received message,
message:the payload of the received message and
packet:the received MQTT packet.
errorevent is emitted when an error occurs in the MQTT client, such as a connection error or a parsing error. This event can be used to handle errors and perform actions based on the type and severity of the error. The handler for this event may receive one of the following TLS errors:
offlineevent is emitted when the MQTT client is disconnected from the broker and cannot reconnect automatically. This event can be used to perform actions that depend on the client being offline, such as stopping processes or sending alerts.
closeevent is emitted when the MQTT client’s connection to the broker is closed, intentionally or due to an error. This event can be used to perform actions that depend on the client being disconnected, such as cleaning up resources or logging data.
Note: For information on handling and working with MQTT packets directly for some of the events above, see the “Dealing with MQTT Packets” section below.
The event callback system in MQTT.js allows for creating robust and flexible MQTT applications that can handle a wide range of scenarios and requirements.
A few examples to illustrate how to utilize events in your code:
Sometimes, the connection to the MQTT broker may be lost due to network issues or other reasons.
MQTT is exceptionally well adapted to manage sessions across disconnections. For more information, see Persistent Session and Queuing Messages - MQTT Essentials: Part 7.
This section explains how the MQTT.js client reconnects in case of loss of connection.
By default, the MQTT.js client will retry connections every 1000ms. See the next section on how to configure this.
When connections are lost, they will be automatically retried. We can use the
reconnect event of the MQTT client instance to perform any related tasks. These tasks might include republishing a message or resubscribing to a topic.
reconnectPeriod option in the MQTT.js package specifies the time interval in milliseconds between reconnection attempts when the connection to the MQTT broker is lost. Here’s an example of how to use the
Quality of Service levels
MQTT supports three different Quality of Service (QoS) levels:
- QoS 0: At most once delivery
- QoS 1: At least once delivery
- QoS 2: Exactly once delivery
These levels are explained in more detail in MQTT Quality of Service (QoS) 0,1, & 2 – MQTT Essentials: Part 6.
To specify the QoS level when publishing a message, we can pass an object as the third argument to the
publish method with the
qos property set to the desired QoS level.
In the above example, we are publishing the message
'Hello, HiveMQ!' to the topic
location/gps/vehicle1 with a QoS level of 1.
Learn more about MQTT Quality of Service Levels in MQTT Quality of Service (QoS) 0,1, & 2 – MQTT Essentials: Part 6.
Last Will and Testament
MQTT supports the Last Will and Testament (LWT) feature, which allows a client to specify a message to be sent by the broker if the client disconnects unexpectedly.
To learn more about the Last Will and Testament feature of MQTT, see Last Will and Testament - MQTT Essentials: Part 9.
To specify the LWT message, we can use the
will option when creating the MQTT client instance.
The LWT message in the above example will be sent to the topic
location/gps/vehicle with a payload of
'Goodbye, HiveMQ!', a QoS level of 1, and the
retain option set to
Learn more about MQTT Last Will & Testament in Last Will and Testament - MQTT Essentials: Part 9.
Topic Alias Management
Topic alias management is a feature introduced in MQTT version 5 that allows clients to use a short numeric identifier (alias) instead of a full topic string in publish and subscribe messages. This can reduce the size of MQTT packets and improve network performance.
The MQTT.js package supports topic alias management in MQTT version 5, and it also provides an option
autoUseTopicAlias to automatically use topic aliases when possible. Here’s an example of how to use topic aliases with
The first call to publish registers the topic alias. And even though we specified the topic again in the second
publish call, internally, the MQTT.js package will use the topic alias in the actual packet sent on the wire.
autoUseTopicAlias, we can improve network performance by automatically using topic aliases when possible. However, it’s important to note that topic aliases should only be used when both the client and the broker support MQTT version 5 and topic alias management.
Of course, the HiveMQ MQTT broker fully supports this and all of the other advanced features of the MQTT specification.
Another related option is
autoAssignTopicAlias. It is used to automatically assign a topic alias to a published message if the topic name has been previously used in a message. Like the previous option, this also reduces the size of MQTT messages by replacing the topic name with a shorter alias - except automatically:
In short, MQTT Topic Alias is an efficiency and performance feature of MQTT. If possible, it should be enabled and utilized to lower the network burden of transmitting long topic names repeatedly.
Closing the Connection
To close an MQTT connection using the MQTT.js library, you can call the end() method on the MQTT client object.
Here’s an example:
In some cases, it may be necessary to immediately terminate the connection without waiting for in-flight messages to be acknowledged, for example, if the connection is no longer needed and needs to be closed quickly.
To do this, you can call the end() method with the force argument set to true, like this:
And there are more options. In all, the
end call accepts three parameters:
|Boolean||When set to |
|Object||The options for the call.|
|Object||The code to execute when the client is closed.|
|Integer||Represents the reason code for the DISCONNECT message sent to the broker when closing the connection. Can be used to provide additional information about the reason for disconnecting, such as an error code or status. See the MQTT Specification for a list of Reason Codes.|
|Object||Contains additional properties to include in the DISCONNECT message sent to the broker when closing the connection. Can be used to provide additional metadata or context about the disconnect, such as the client identifier or session expiry.|
|Number||Specifies a new Session Expiry Interval for the broker.|
|String||Provides additional context or information about the reason for disconnecting.|
|Object||Contains additional user-defined properties to include in the message.|
Close the Connection with a Reason Code
As an example, if we wanted to disconnect gracefully but still have the Last Will & Testament message sent:
Note: Get the list of valid Reason Code values directly from the MQTT v5 Specification
Learn more about MQTT Last Will & Testament in Last Will and Testament - MQTT Essentials: Part 9.
Close the Connection and Update the Session Expiry Interval
To send an updated Session Expiry Interval when disconnecting:
Learn more about MQTT Session Expiry Intervals in Session and Message Expiry Intervals - MQTT 5 Essentials Part 4.
Dealing with MQTT Packets
Internally, the MQTT.js package doesn’t generate or parse any MQTT packets. That functionality lives in another package:
mqtt-packet package is a standalone Node.js package that offers low-level MQTT packet parsing and serialization functionality. It is used internally by the MQTT.js package to encode and decode MQTT packets.
It provides methods for encoding MQTT packets into binary data and decoding binary data into MQTT packets. It also provides a set of constants for MQTT packet types, packet flags, QoS levels, and error codes.
If you have to work with MQTT packets directly, such as in the case of some of the MQTT.js events discussed above, see the
mqtt-packet package for details on packet properties and abilities.
The source code for the
mqtt-packet package with a good amount of documentation is available on Github.
Promises and async-mqtt
Promises were introduced into Node.js in version 0.12 in 2015. Promises are objects that represent the eventual completion (or failure) of an asynchronous operation and allow us to chain multiple asynchronous operations together in a more structured way.
The async-mqtt package is a wrapper around the MQTT.js library that adds support for promises making it easy to work with asynchronous operations in an MQTT application.
Here’s an example of how to use promises in the async-mqtt package:
Note the use of the
async keyword to make the
on event handler function asynchronously and use the
await keyword to wait for the completion of the
Errors can occur in a variety of situations, such as when connecting to a broker, publishing or subscribing to messages, or when the network connection is lost. Implementing proper error handling in your code is crucial to ensure the reliable operation of your MQTT client application and effectively manage any errors that may occur.
There are two general ways to handle errors with the MQTT.js package.
- The global
errorevent is emitted when an error occurs in the MQTT client, such as a connection error or a parsing error.
- Per operation error handlers
Error handling is crucial to developing reliable MQTT client applications using the MQTT.js package. Handling errors allows the application to respond appropriately to various scenarios that can cause the MQTT client to fail or lose connectivity to the broker.
By properly handling errors, applications operate more reliably, predictably, and helps in diagnosis when problems arise.
To enable debug logging in the MQTT.js package, simply set the environment variable
The MQTT.js package includes a command line interface (CLI) tool named
mqtt that provides a convenient way to interact with MQTT brokers and perform various operations, such as publishing and subscribing to topics, using the command line. This is an excellent option to assist in the development, testing, and debugging of problems.
To get it, install the MQTT.js package globally using the npm package manager. You can do this by running the following command in your terminal:
From there, you can then subscribe to topics, publish messages and more. Try the following two commands in different shell sessions:
Designing and Implementing MQTT Payloads
Now that you know about the MQTT operations, what do you put in the payload? Will the receiving end understand and be able to decode the data correctly? This is a problem beyond the scope of MQTT, which just provides the transport.
Designing and implementing MQTT payloads involves several considerations, including the size, format, and encoding of the payload data. Here are some guidelines for designing and implementing MQTT payloads:
- Size - MQTT payloads should be as small as possible to reduce network traffic and improve performance. Consider the size of the data you want to send and try to minimize it when possible.
- Format - MQTT payloads can be formatted in several ways, including JSON, XML, or even binary. The choice of format depends on the requirements of the application and the capabilities of the MQTT client and broker.
- Encoding - MQTT payloads should be encoded in a format supported by both the MQTT client and the receiver. Common encodings include UTF-8, ASCII, and binary formats.
- Topic structure - MQTT topics should be structured in a way that is easy to understand and maintain. Consider using a hierarchical topic structure that is easy to navigate and organize.
- QoS level - MQTT payloads can be published with different QoS levels, which determine the reliability and delivery guarantees of the message. Consider the QoS level of the message when designing the payload and ensure that it is appropriate for the application’s requirements.
Here’s an example of how to design and implement an MQTT payload in JSON format:
This JSON payload is small and easy to read and can be easily parsed and processed by another MQTT client that supports JSON decoding.
It’s important to consider the requirements of the application and the capabilities of the MQTT client and broker. The aim is to create efficient and effective MQTT payloads that meet the needs of the MQTT application.
IoT and MQTT Sparkplug
Regarding payloads, the MQTT Sparkplug specification deals precisely with this. It provides a standardized approach to using MQTT in industrial applications and defines a set of guidelines for message payload format, topic structure, and QoS levels.
Industrial IoT applications typically involve complex, large-scale systems with many devices and sensors. These systems often have strict requirements for reliability, scalability, and real-time performance. MQTT provides a flexible and scalable protocol for connecting devices and transmitting data. Without a standardized approach, it can be challenging to ensure compatibility and interoperability between devices and systems. As the number of connected devices grows, so does the complexity if it’s not well managed.
The MQTT Sparkplug specification addresses these obstacles by providing a standardized approach to using MQTT. It defines a set of guidelines for message payload format, topic structure, and QoS levels that ensure compatibility and interoperability between devices and systems.
It also defines a set of data structures and payload formats optimized for industrial IoT applications. These data structures include device and sensor data, alarms, events, and commands. The payload formats are designed to be efficient, compact, and easily parsed by MQTT clients and brokers.
And finally, it defines a set of guidelines for topic structure and QoS levels. The topic structure is hierarchical and follows a standardized naming convention that makes navigating and organizing MQTT topics easy. The QoS levels are carefully chosen to balance reliability and performance and ensure that data is delivered promptly and efficiently.
The MQTT Sparkplug specification provides a standardized approach to using MQTT that ensures compatibility and interoperability between devices and systems.
Best MQTT Broker
Do you need an MQTT broker for your project? HiveMQ Cloud offers a hosted and fully managed broker so you can focus on your applications. It’s free for the first 100 device connections.
Alternatively, you could run the broker locally with
docker run --name hivemq-ce -d -p 1883:1883 hivemq/hivemq-ce. The source code to the community edition is on Github.
If you have a larger project, the HiveMQ broker can scale up to 200 million devices!
We have thoroughly explored how to use MQTT in Node.js. We have covered how to connect to an MQTT broker, subscribe to topics, publish messages, reconnect, use Quality of Service levels, use Last Will and Testament and much more.
We at HiveMQ hope you found this guide helpful and wish you the best of luck in your MQTT adventures. If some questions arise along the way, we are always happy to help! Come visit our Community Forums and join us in the MQTT discussion.
If you need a reliable, secure, performant and the best MQTT broker available by far, check out HiveMQ Cloud - we’d be honored to have you as a user.
Here are some valuable links you are likely to need during the course of development.
Code, Libraries and Packages
- HiveMQ Blog
- HiveMQ Youtube Channel
- MQTT Essentials Blog Series
- MQTT v5 Video Series
- Sparkplug Essentials Video Series
- HiveMQ Cloud Broker - free to connect up to 100 devices (no credit card required)
- HiveMQ Broker Community Edition -
docker run -p 1883:1883 hivemq/hivemq-ce