An MQTT broker for mobile apps lets a phone see device data the moment it changes and send commands back with very little overhead. This guide explains how mobile apps should connect, when MQTT is the right tool and when platform push notifications are, how to keep battery use low, and how to handle credentials safely, with a working example against ConnectMQ.
Why Mobile Apps Use MQTT
Mobile IoT apps usually need three things: show live state (is the door locked, what is the tank level), send commands (turn on the pump), and react quickly to changes. Polling a REST API every few seconds delivers all three badly: it wastes battery and data, adds latency and loads your backend. MQTT keeps one long-lived connection open while the app is active and pushes only what changed.
The broker in the middle decouples the app from devices. The phone never needs a device's IP address; both sides talk to a known endpoint. If you are new to that role, read what an MQTT broker does first.
Connection Options from a Phone
| Transport | URL | When to use |
|---|---|---|
| MQTT over TLS | mqtts://broker.connectmq.com:8883 |
Native apps with a TCP-capable MQTT library (Kotlin, Swift, Flutter) |
| MQTT over Secure WebSocket | wss://broker.connectmq.com:8084/mqtt |
React Native, Ionic, PWAs and webviews; networks that block 8883 |
Both are encrypted and both work with MQTT 3.1.1 and 5.0. WebSocket is often the path of least resistance in JavaScript-based apps and on restrictive Wi-Fi networks; native TLS is marginally more efficient. Never use the unencrypted ports 1883 or 8083 from a production app. The MQTT over WebSocket guide explains the WebSocket transport in depth.
MQTT vs Push Notifications
This is the most important design decision, and the answer is usually "both".
| Need | MQTT | Platform push (APNs / FCM) |
|---|---|---|
| Live updates while app is open | Excellent | Poor fit |
| Alerts while app is closed | Not reliable | Designed for this |
| Two-way commands | Yes | No |
| Battery cost in background | High if kept open | Handled by the OS |
| Delivery when phone is offline | Persistent session while it lasts | Queued by the platform |
Mobile operating systems suspend background apps and their sockets. iOS in particular will not let you hold an MQTT connection open indefinitely in the background. So the robust architecture is:
- Foreground: the app connects to the broker, subscribes to the devices the user is viewing and sends commands over MQTT.
- Background: the app disconnects cleanly. A small backend service subscribes to alert topics on the broker and sends platform push notifications when something important happens.
- Return to foreground: the app reconnects, retained messages immediately deliver the current state, and the UI is up to date within moments.
The backend relay in step 2 is just another MQTT client you run, for example a Node.js or Python service. ConnectMQ does not send push notifications itself, and keeping that logic in your own service gives you control over which events become notifications.
Battery and Data Considerations
- Connect only while needed. Open the connection when the relevant screen appears and close it when the app goes to the background.
- Subscribe narrowly. Subscribe to
home/42/devices/+/state, not#. Every message you receive costs radio time. - Use retained messages for state. The app gets the last known value instantly on subscribe, so you never need to poll or request a refresh.
- Pick a moderate keep alive. 30 to 60 seconds balances quick detection of dead connections with fewer radio wake-ups.
- Keep payloads compact. Short JSON keys or binary encodings help on cellular links.
- Use MQTT 5 topic aliases and message expiry where supported. Aliases shrink repeated long topic names; message expiry stops stale commands from being delivered late.
- Back off on reconnect. Mobile networks change constantly; exponential backoff avoids tight retry loops that drain the battery.
Working Example: React Native or Web with MQTT.js
MQTT.js runs in browsers and React Native over WebSocket. This module encapsulates connect, subscribe and app lifecycle handling.
import mqtt from "mqtt";
const BROKER_URL = "wss://broker.connectmq.com:8084/mqtt";
export function createDeviceConnection({ clientId, username, password, homeId, onState }) {
const client = mqtt.connect(BROKER_URL, {
clientId,
username,
password,
protocolVersion: 5,
keepalive: 45,
clean: true,
reconnectPeriod: 3000,
connectTimeout: 10000,
});
const stateTopic = `homes/${homeId}/devices/+/state`;
client.on("connect", () => {
client.subscribe(stateTopic, { qos: 1 }, (err) => {
if (err) console.warn("Subscribe failed", err.message);
});
});
client.on("message", (topic, payload) => {
const deviceId = topic.split("/")[3];
try {
onState(deviceId, JSON.parse(payload.toString()));
} catch {
console.warn("Ignoring non-JSON payload on", topic);
}
});
client.on("error", (err) => console.warn("MQTT error", err.message));
return {
sendCommand(deviceId, command) {
client.publish(
`homes/${homeId}/devices/${deviceId}/cmd`,
JSON.stringify(command),
{ qos: 1, properties: { messageExpiryInterval: 30 } }
);
},
pause() {
client.end(false);
},
resume() {
if (!client.connected) client.reconnect();
},
};
}
In React Native, call pause() and resume() from an AppState change listener. The 30-second message expiry means a command queued while a device is offline will not unexpectedly fire minutes later. Some React Native setups need a WebSocket or Buffer polyfill; check the React Native MQTT guide for platform specifics, and Flutter MQTT if you build with Dart.
To try this without an account, point it at the free public MQTT broker, omit username and password, use any non-empty unique client ID and prefix topics with something unique such as connectmq/demo/m7d2w/homes/.... Everything in the public area is readable by anyone, so use it only for demos.
Handling Credentials Safely
A mobile app binary can be decompiled, so treat anything embedded in it as public.
- Do not ship one shared broker password in the app. If it leaks, every user's traffic is exposed and you cannot revoke it without breaking every install.
- Issue credentials per user or per session from your backend. After the user signs in to your app, your API returns the MQTT credentials and client ID that user should use.
- Scope topics by user or home. Design topics so each user's data sits under its own prefix, and enforce on the device and backend side which commands are accepted from whom.
- Rotate and revoke. When a user signs out or a phone is lost, revoke its credentials.
- Validate commands on the device or backend. Never trust that a command came from a legitimate screen.
ConnectMQ binds client IDs to issued credentials and blocks IPs after repeated failed logins, which helps against credential stuffing. Read MQTT security best practices for the full list.
Capacity Planning for Apps
Every open app is one connection. Ten devices and fifty active app users is sixty concurrent connections at peak, not ten. ConnectMQ Serverless (Free) allows up to 25 connections, which suits development and a small beta; Serverless (Paid) goes up to 1,000 connections with QoS 2 and shared subscriptions; dedicated clusters handle larger audiences. Because apps disconnect in the background, concurrent connections are usually far fewer than installs, but measure your real pattern rather than guessing.
For the hosting options behind these plans, see the cloud MQTT broker guide.
Connect Your App to ConnectMQ
Create a free Serverless broker at app.connectmq.com with no credit card, test your topics in the in-browser client, and point the MQTT.js example at your new endpoint. ConnectMQ is a managed MQTT broker with TLS and Secure WebSocket endpoints ready for mobile clients from the first minute.
Frequently Asked Questions
Can a mobile app keep an MQTT connection open in the background?
Not reliably. Mobile operating systems suspend background sockets, so use MQTT while the app is in the foreground and platform push notifications for background alerts.
Should a mobile app use WebSocket or TCP for MQTT?
JavaScript-based apps usually use Secure WebSocket on port 8084 with path /mqtt. Native apps can use TLS on 8883; both are encrypted.
How do I get the current device state when the app opens?
Have devices publish state as retained messages. The broker delivers the latest value immediately when the app subscribes.
Is it safe to embed broker credentials in a mobile app?
No. Issue per-user credentials from your backend after sign-in so a leaked credential can be revoked individually.



