mqtt.js clients can connect to brokers using a staggering array of options, but most users only need a handful to get reliable communication.
Let’s see it in action. Imagine we’re building a simple IoT dashboard. We need to connect a Node.js client to a local Mosquitto broker running on localhost:1883.
const mqtt = require('mqtt');
const client = mqtt.connect('mqtt://localhost:1883', {
clientId: 'myNodeClient_' + Math.random().toString(16).substr(2, 8),
clean: true, // Start with a clean session
connectTimeout: 4000, // Timeout after 4 seconds
reconnectPeriod: 2000, // Try reconnecting every 2 seconds
keepalive: 60 // Send PINGREQ every 60 seconds
});
client.on('connect', () => {
console.log('Connected to MQTT broker!');
client.subscribe('home/+/temperature', (err) => {
if (!err) {
console.log('Subscribed to home/+/temperature');
} else {
console.error('Subscription failed:', err);
}
});
});
client.on('message', (topic, message) => {
console.log(`Received message on topic ${topic}: ${message.toString()}`);
});
client.on('error', (err) => {
console.error('Connection error:', err);
client.end(); // Gracefully close the connection
});
client.on('close', () => {
console.log('Connection closed');
});
client.on('offline', () => {
console.log('Client is offline');
});
This code establishes a connection, subscribes to a wildcard topic, and logs incoming messages. The clientId is crucial; if omitted, mqtt.js generates one, but explicitly setting it allows for better tracking and avoids potential conflicts if multiple clients with the same generated ID try to connect. The clean: true option ensures that any previous session state is discarded, providing a fresh start. This is generally preferred for most client applications unless you specifically need session persistence.
The connectTimeout option dictates how long the client will wait for the broker to acknowledge the connection attempt. If the broker doesn’t respond within this timeframe (here, 4000 milliseconds or 4 seconds), the client will consider the connection failed. This prevents the client from hanging indefinitely if the broker is unreachable. reconnectPeriod defines the interval between reconnection attempts if the connection is lost. A value of 2000 milliseconds (2 seconds) means the client will try to re-establish a connection every two seconds. This is a balance: too short, and you might overwhelm a struggling broker; too long, and your application stays offline for an extended period.
The keepalive setting is fundamental for maintaining an active connection. It’s the maximum interval, in seconds, that the client will allow to pass without receiving a message from the broker. If this interval is exceeded, the client sends a PINGREQ packet to the broker. The broker, if alive, responds with a PONG. This handshake confirms that both parties are still online. If the broker doesn’t respond to a PINGREQ within a reasonable time (often related to the keepalive value, though not strictly defined by the MQTT spec for the client side), the client will assume the connection is broken and initiate a reconnect sequence. For typical local networks, a keepalive of 60 seconds is common. For unreliable or high-latency networks, you might decrease this value to detect disconnections sooner.
Beyond these, you might encounter scenarios requiring TLS/SSL for secure connections, username/password authentication, or Last Will and Testament (LWT) messages. For TLS, you’d provide tls: { rejectUnauthorized: false } (for development/self-signed certs) or proper certificate paths. Authentication is handled via username and password properties within the options object. LWT involves setting will: { topic: 'home/myNodeClient_/status', payload: 'offline', qos: 0, retain: true } in the connection options. The LWT message is sent by the broker if the client disconnects unexpectedly.
One crucial detail many overlook is how clientId interacts with session management. If clean: false is used, the broker attempts to resume a previous session associated with that clientId. This means retained messages and subscriptions from the prior session are restored. However, if the client restarts and its internal state (e.g., cached message IDs for QoS 1/2) is out of sync with what the broker expects for that resumed session, you can encounter unexpected behavior or errors. Always ensure your client logic can handle potential message redeliveries or out-of-order messages when clean: false is employed.
The next hurdle is understanding Quality of Service (QoS) levels and their implications for message delivery guarantees.