Connectivity and security
Connecting a STOMP client to KubeMQ — the KUBEMQ_STOMP_URL convention, ports 61613/61614, the CONNECT handshake, heartbeats, and TLS on 61614.
The KubeMQ STOMP connector is an embedded STOMP server inside kubemq-server with its own
dedicated listeners — plain TCP 61613 (default) and TLS 61614 (default). An existing STOMP
application connects to it by changing only the broker address. This guide covers the connection URL
convention, the CONNECT handshake, heartbeats, TLS, and the connection limit.
KUBEMQ_STOMP_URL — the connection convention
The connector reads KUBEMQ_STOMP_URL (default tcp://localhost:61613) and dials it. The URL
scheme selects the transport:
export KUBEMQ_STOMP_URL="tcp://localhost:61613" # default — plain TCP listener (port 61613)
# export KUBEMQ_STOMP_URL="tls://kubemq.example:61614" # TLS listener (port 61614, see below)| Scheme | Transport | Listener (default port) |
|---|---|---|
tcp:// | plain TCP | 61613 |
tls:// | TLS | 61614 (active only when the server Security block resolves to TLS) |
The connector binds all interfaces (:<port>), not just localhost. Both ports are configurable
via the connector configuration.
Verify the listener — do not infer it from a successful server boot. The connector loader is
availability-first: a bind failure logs a warning and the server keeps running without STOMP.
Confirm the listener is up via the /stomp web dashboard, the kubemq_stomp_connections Prometheus
gauge, or GET /api/stomp/connections.
The CONNECT handshake
Every connection opens with the same CONNECT frame and reads the negotiated CONNECTED headers
back:
CONNECT
accept-version:1.2 # highest common of 1.0/1.1/1.2; absent/empty → 1.0
heart-beat:10000,10000 # client cx,cy in ms; server advertises sx=sy=HeartbeatMs (default 10000)
login:my-app # freeform (session id fallback when no JWT claims)
passcode: # empty/any in the default no-auth mode
^@The CONNECTED reply carries:
| Header | Value |
|---|---|
version | the negotiated version (1.0 / 1.1 / 1.2) |
heart-beat | the server's advertised sx,sy (both = HeartbeatMs), not the negotiated effective values |
session | the derived client id (see Authentication) |
server | KubeMQ/<version> |
CONNECTED headers are never escaped (handshake exemption). The handshake order is: version
negotiation → broker-ready gate → max-connections check → auth → derive client id → heartbeat
negotiation → send CONNECTED.
accept-version:1.2 is recommended. See Protocol versions
for the negotiation rules and the per-version feature matrix.
Heartbeats and the 2x dead-peer cutoff
Heartbeats keep the TCP connection alive and let the connector detect a dead peer.
- The client sends
heart-beat:cx,cy(ms). The server advertisessx = sy = HeartbeatMs(default 10000;0disables the server side). - Effective client→server interval =
maxNonZero(cx, sy); server→client =maxNonZero(sx, cy)— wheremaxNonZero(a, b)is0if either side is0(that direction is disabled), otherwisemax(a, b). - Parsing is lenient: a missing, non-numeric, negative, or 3-field value becomes
0,0.
The dead-peer cutoff is 2x the negotiated client→server interval. The watchdog force-closes the
connection (audited as client.timeout) if no inbound bytes arrive within that window. Any inbound
byte — a real frame or a bare \n heartbeat — refreshes liveness. The server sends a heartbeat LF
only when it has written nothing for at least half the server→client interval.
Recommendation: send heart-beat:10000,10000 (matches the server default). With a 10 s
client→server interval the cutoff is 20 s — a client must send a frame or a bare \n before that
window elapses.
TLS
TLS is a transport swap — the STOMP protocol on top is unchanged. Point KUBEMQ_STOMP_URL at
tls://host:61614 and configure the server Security block; the STOMP frames are identical.
export KUBEMQ_STOMP_URL="tls://kubemq.example.com:61614"- The TLS listener is the default port 61614 (
tls://...). - It is active only when the TLS port is configured and the server-wide
Securityblock resolves to non-nil TLS. If the Security mode isnone, the TLS port is silently skipped. - TLS has no STOMP-specific config. The certificate material, mTLS, and minimum version all come
from the server-wide
Securityblock — the connector owns only whether the TLS port is open. mTLS requires and verifies the client certificate; the minimum is TLS 1.2.
For the shared KubeMQ JWT model and TLS/mTLS concepts across connectors, see Auth & security.
WebSocket is not supported in V1
The connector is raw TCP only. STOMP-over-WebSocket is a documented future listener path, not
a current feature. The popular browser/Node client @stomp/stompjs speaks STOMP only over
WebSocket, so it cannot connect to the raw-TCP listener directly. The JavaScript/TypeScript
examples therefore use stompit (raw TCP).
Connection limit
The connector enforces a maximum connection count (default 1000; 0 = unlimited). The slot is
counted at accept — a raw TCP socket that never sends CONNECT still consumes a slot — but the
over-limit ERROR "connection limit reached" is deferred to the handshake so the client receives
a proper frame.
Errors are terminal
Every protocol error produces an ERROR frame followed by a socket close. The message is
sanitized — internal error text never crosses the wire. Treat every ERROR frame as terminal in
client code, and reconnect if appropriate.
Related
Authentication
The login/passcode part of the CONNECT frame — the KubeMQ JWT, derived session ids, and Casbin authorization.
Protocol versions
Version negotiation and the 1.0/1.1/1.2 feature matrix — escaping, ack tokens, and subscription ids.
Auth & security
The shared KubeMQ JWT model and TLS/mTLS concepts across connectors.
Was this page helpful?
Commands
Requester-only RPC commands over STOMP — the /command/ destination prefix, the 3-step reply-to flow, and the stomp-error failure header on KubeMQ Commands.
Destination mapping
How the KubeMQ STOMP connector maps a destination to a pattern and channel — the prefix grammar, slash-to-dot joining, aliases, and Events-only wildcards.