Most of it breaks below the layer you suspect.

Engineers who built and scaled Courier, the open-source MQTT platform behind a Southeast Asian super-app, load tested to a million concurrent connections.

Five ceilings on the way to a million. Four broke below the broker, two of those at the load balancer. /  Load test, not a production peak.

Evidence

Seven product surfaces, one connection.

Chat, order status, driver matching, live location and three more arrive on a single long-lived socket. Under it sit six layers no product roadmap has room for, and the load test broke at five ceilings across three of them. The broker's own was the fourth of the five. That is why a diagnosis starts below the layer you suspect.

What sits on one long-lived connection, and where it broke. Seven product surfaces run on the application layer. Six layers below it carry the work downstack does, graded by what is true of each: built, absorbed or tuned. Five load-test ceilings are recorded at the layer each one broke at. Sources: Acing 1 Million Concurrent MQTT Connections, gojek.io, Apr 15, 2022, for the ceilings; Introducing Courier: The Information Superhighway Between Mobile and Server, gojek.io, Aug 10, 2021, for the product surfaces. The ceilings are a load test, not a production peak.
Application, product surfacesan order reaches a merchant (to the device); order status reaches the customer (to the device); a trip finds a driver (both ways); a vehicle moves on the map (from the device); a customer messages support (both ways); a push notification arrives (to the device); the app reports what people do (from the device)
CLIENT LIBRARYbuilt: reconnect, keepalive, backoff. No load-test ceiling recorded at this layer.
Device OS and radioabsorbed: Doze, background limits, battery. No load-test ceiling recorded at this layer.
THE NETWORKabsorbed: carrier NAT, captive portals, half-open TCP. No load-test ceiling recorded at this layer.
Host and kerneltuned: ephemeral ports, file descriptors. Ceiling at 28,200 / VM connections, ephemeral port exhaustion. Ceiling at 40,000 connections, EMFILE, file descriptor limit.
LOAD BALANCERtuned: TLS termination, connection limits. Ceiling at 113,000 connections, proxy port exhaustion. Ceiling at 710,000 connections, proxy connection cap, raised.
BROKERtuned: VerneMQ listeners, queues, sessions. Ceiling at 362,000 connections, listener connection limit.
Ceilings: Acing 1 Million Concurrent MQTT Connections, gojek.io, Apr 15, 2022. Load test, not a production peak.Surfaces: Introducing Courier: The Information Superhighway Between Mobile and Server, gojek.io, Aug 10, 2021.

Three opinions

Our point of view.

01

Start at the business SLA, not the stack.

The only one of these that works on someone who is not an engineer. What has to arrive, how fast, and what it costs when it does not, before anyone opens a broker config.

02

The problem is rarely where it surfaces.

Sometimes it genuinely is the broker: the VerneMQ listener limit at 362,000 was real, and forking it was the fix. We still check the layers underneath first, because four of the five ceilings were down there and two of those were the load balancer.gojek.io, Apr 15, 2022

03

If you cannot say what your push delivery rate is, you do not have one.

A delivery rate nobody has measured is an assumption with a number attached. The figure below is what the measured version looks like.gojek.io, Oct 23, 2023

The receipt

Push delivery, measured.

Push notification services alone against an MQTT-first path that falls back to them. The axis is truncated, because the whole argument lives in the last thirty points of it.

Measured push delivery rates. Source: gojek.io, published Oct 23, 2023. The horizontal axis begins at 70 percent, not zero.
PathMeasured delivery
push alone, FCM and APNs, no persistent socket75 to 85 percent
mqtt-first, push fallback, an app mostly in the background95 percent or better
mqtt-first, push fallback, apps mostly in the foreground99 percent or better
Axis begins at 70%, not zero. Marks are measured intervals and floors, not totals.Source: gojek.io, published Oct 23, 2023.

What we do

Reliable real-time between an app and the backend behind it.

Messages that arrive, on real networks and real handsets, without burning the battery or falling over at the connection count you need. We are a consultancy of engineers who work on every layer that decides whether they do: the client, the radio, the reconnect, the load balancer, the kernel, the broker's internals.

01

Broker scaling and capacity planning

Your broker stops falling over at the connection count you need, and you know where the next ceiling is before you hit it. Which layer sets it, and what it costs to move it. In practice that means MQTT brokers, and VerneMQ is the one we have taken apart.

02

Debugging connection-level incidents

Someone can find the cause when connections silently stop delivering and nothing is obviously broken. Half-open sockets, silent reconnect storms, QoS 1 that is acknowledged and still does not arrive.

03

Staying connected on Android without draining the battery

The app holds its connection instead of being killed by the OS. Doze, background execution limits, and MQTT keepalive intervals that survive a real handset rather than an emulator.

04

Broker modification and forking

The broker behaves the way your architecture needs, instead of the architecture bending around the broker. When the ceiling is inside it and the upstream answer is not coming. gojek/vernemq is public; that is what this looks like.

Not ours, and we will say so early: MQTT 5, browser or web real-time, industrial, automotive.

On the record

Public, dated, checkable in a minute.

The 900-Second Ghost: Debugging Half-Open TCP

KubeCon + CloudNativeCon India and PlatformCon.

Talk / 2026

Acing 1 Million Concurrent MQTT Connections

The source for the first figure's ceilings: all five in full, with the fix for each one.gojek.io

Write-up / Apr 15, 2022

More of it, annotated: the eight Courier posts written by members of this team are listed on writing, each with a figure taken from it and a line on what it is evidence for.

Who we are

Four people, four layers.

A message crosses the app, the radio, the network, the load balancer, the kernel and the broker before anyone sees it. The team is shaped the same way.

Ajat Prabha

Server-side and Go

Works on the backend half of the connection. They published the first release of the open source Go client and are its second-highest committer at 78 commits.gojek/courier-go contributors, observed Aug 8, 2026

Dhruv Jain

Broker operations, and below

Works under the protocol: TCP, kernel limits, load balancers, connection tracking. They authored the load-test write-up the first figure is drawn from, and hold the only independently verified conference speaking credit here.gojek.io, Apr 15, 2022 / KubeCon + CloudNativeCon India and PlatformCon, 2026

Deepanshu

Android and the mobile client

Works on keeping an app connected on a handset that is trying to sleep. They are the most published author on the Courier series.Courier blog index, observed Aug 8, 2026

Anubhav Gupta

Mobile real-time architecture

Works on which transport a product should be betting on. They wrote the post that introduced Courier publicly and made the architectural case for MQTT over gRPC and WebSocket on battery grounds.gojek.io, Aug 10, 2021

How an engagement is staffed: one principal leads it end to end, and the others are scheduled in as named specialist depth where their layer is in scope.

How to start

A connection-layer assessment.

Fixed scope, two to three weeks. It ends in a written diagnosis and a prioritised fix plan that you keep, whether or not anything follows it.

The shape of it: we diagnose, design, modify and hand back, and every engagement carries a written exit condition agreed at the start.