Migrating from ActiveMQ
Route ActiveMQ onto KubeMQ by client type — JMS via Qpid JMS, STOMP and MQTT by endpoint; OpenWire is not supported.
ActiveMQ is a multi-protocol broker, so there is no single migration path. Which connector you use — and which guide you follow — depends on which protocol your client speaks and which ActiveMQ variant (Classic or Artemis) you run. This page is the router: it points you at the right per-protocol guide and calls out the one thing that does not migrate at all.
KubeMQ serves ActiveMQ workloads through three existing connectors — AMQP 1.0, STOMP, and
MQTT — depending on the protocol. All three are opt-in (Enable = false by default); you
enable only the connector(s) your clients need. The per-protocol guides carry the full code; this
page keeps the endpoint deltas and the cross-cutting deviations in one place.
OpenWire is NOT supported. KubeMQ has no OpenWire wire decoder. Any client connecting over the OpenWire protocol will fail. There is no configuration option to add OpenWire support — an ActiveMQ client using the default OpenWire transport must switch to AMQP 1.0, STOMP, or MQTT before it can talk to KubeMQ.
Choose your path
Pick the row that matches your client, then follow the linked guide for the connection snippet, destination mapping, and a working code example.
| Client type | ActiveMQ variant | Connector | Guide |
|---|---|---|---|
| Java / JMS applications | Classic or Artemis | AMQP 1.0 (via Apache Qpid JMS) | Migrating from JMS |
| Non-Java clients using STOMP | Classic or Artemis | STOMP | Migrating from STOMP |
| Non-Java clients using MQTT | Classic or Artemis | MQTT | Migrating from MQTT |
| Native AMQP 1.0 clients | Artemis (native AMQP 1.0) | AMQP 1.0 | Migrating from AMQP 1.0 |
Java/JMS applications keep their JMS code and swap only the ConnectionFactory implementation to
Apache Qpid JMS — a client-swap. STOMP, MQTT, and native AMQP 1.0 clients are endpoint-only:
change the broker host and credentials, nothing else.
Default ports (when the connector is enabled):
| Connector | Port | TLS port | Protocol |
|---|---|---|---|
| AMQP 1.0 | 5672 | 5671 | AMQP 1.0 (Qpid JMS, Artemis) |
| STOMP | 61613 | 61614 | STOMP 1.0 / 1.1 / 1.2 |
| MQTT | 1883 | 8883 (WS 8083) | MQTT 3.1.1 / 5.0 |
Enable only what you need. Each connector has its own enable variable:
CONNECTORS_AMQP10_ENABLE=true # Java/JMS via Qpid JMS, and native AMQP 1.0 (Artemis) clients
CONNECTORS_STOMP_ENABLE=true # STOMP clients (Classic and Artemis)
CONNECTORSMQTT_ENABLE=true # MQTT clients (note: no underscore)Compatibility Matrix
This matrix is self-contained for the ActiveMQ workload across all three connectors. Where a capability differs by path, the cell names the path it applies to.
| Dimension | Status | Notes |
|---|---|---|
| Drop-in level | client-swap / endpoint | Java/JMS: client-swap (Qpid JMS); STOMP/MQTT: endpoint-only |
| Point-to-point queues | ✅ | All three connectors support Queues |
| Pub/sub (non-durable) | ✅ | Events pattern on all paths |
| Durable subscriptions | ✅ | Via Events Store; unsubscribe() is node-local — see Behavioral deviations |
| Request/reply (RPC) | ✅ ² | AMQP 1.0 (Qpid JMS) path only |
| Ordering | ⚠️ node-local | Per-channel ordering is not preserved cluster-wide |
| Transactions | ❌ | Not supported on any path |
| Dead-letter / redrive | ❌ no client DLQ ⁶ | No client-settable DLQ; poison messages are silently dropped |
| Selectors / filtering | ✅ (AMQP 1.0) / ❌ (STOMP) | SQL92 selectors work on the AMQP 1.0 path (Events / Events Store); no selectors on STOMP |
| Auth model | PLAIN (JWT) | JWT in SASL PLAIN password (AMQP 1.0), CONNECT passcode (STOMP), or CONNECT password (MQTT) |
| TLS / mTLS | ✅ | 5671 (AMQP 1.0), 61614 (STOMP), 8883 / wss 8083 (MQTT) |
| Top unsupported | — | OpenWire protocol; transactions; selectors on the STOMP path |
Footnotes:
- ² ActiveMQ RPC via the AMQP 1.0 (Qpid JMS) path only; STOMP reply-to works but requires a pre-existing reply subscription.
- ⁶ See What Does NOT Migrate → Hard blockers for the authoritative statement.
Connection / Endpoint Migration
The change is the same shape on every path: point the client at the KubeMQ host and supply a KubeMQ JWT as the credential. The full code lives in the linked per-protocol guides — these tabs show only the endpoint delta.
Java applications using the ActiveMQ JMS client (ActiveMQConnectionFactory) migrate by swapping
the ConnectionFactory implementation to Apache Qpid JMS — the JMS application code itself does
not change. Native AMQP 1.0 clients (e.g. go-amqp, AMQP.NET Lite, Qpid Proton) and Artemis
clients that already speak AMQP 1.0 migrate by changing only the broker endpoint.
# Before (ActiveMQ Classic, OpenWire — must switch protocol)
tcp://activemq.example.com:61616
# Before (ActiveMQ Artemis, native AMQP 1.0)
amqp://artemis.example.com:5672
# After (KubeMQ)
amqp://kubemq.example.com:5672
amqps://kubemq.example.com:5671 # TLSFor the JNDI setup, destination mapping, and the full Qpid JMS snippet, see
Migrating from JMS. For the native AMQP 1.0 path
(addressing, message translation, RPC, and the go-amqp snippet), see
Migrating from AMQP 1.0.
# Before (ActiveMQ Classic STOMP)
host: activemq.example.com
port: 61613
# After (KubeMQ STOMP)
host: kubemq.example.com
port: 61613 # same port; TLS on 61614Destination compatibility note: ActiveMQ uses /queue/NAME and /topic/NAME with
.-delimited names. KubeMQ accepts both forms — /topic/orders.created and
/topic/orders/created reach the same KubeMQ channel orders.created. Pick one convention and
apply it consistently.
For destinations, ack modes, durable subscriptions, and the full stomp.py snippet, see
Migrating from STOMP.
# Before (ActiveMQ Classic MQTT)
host: activemq.example.com
port: 1883
# After (KubeMQ MQTT)
host: kubemq.example.com
port: 1883 # plain; TLS on 8883; WS on 8083MQTT version note: KubeMQ rejects MQTT 3.1 clients at CONNECT. Use MQTT 3.1.1 (the default for most clients, including Eclipse Paho) or MQTT 5.0.
For topic→pattern mapping, QoS, and the paho-mqtt snippet, see
Migrating from MQTT.
Concept & Destination Mapping
ActiveMQ concepts map onto KubeMQ patterns through the connector chosen for each client type.
AMQP 1.0 path (Qpid JMS / Artemis)
| ActiveMQ concept | KubeMQ pattern | Channel / address |
|---|---|---|
| Queue | Queues | /queues/<name> |
| Topic (non-durable) | Events | /events/<name> |
| Durable topic subscription | Events Store | /events-store/<name> |
| Temporary queue | Dynamic node (temp reply mailbox) | source.dynamic = true |
| Virtual Topic / shared sub | Consumer group | link property x-opt-kubemq-group |
| Command (request/reply) | Commands or Queries | /commands/<name> / /queries/<name> |
| Reply-to | /responses/<RequestID> or dynamic node | — |
The JMS capability hint (queue / topic) lets Qpid JMS Queue("orders") and Topic("orders")
map automatically without an explicit prefix — see
Migrating from JMS for details.
STOMP path
| ActiveMQ destination | KubeMQ destination | Pattern |
|---|---|---|
/queue/NAME | /queue/NAME | Queues |
/topic/NAME | /topic/NAME | Events |
| Durable topic | /topic-store/NAME | Events Store |
ActiveMQ Virtual Topic VirtualTopic.X | /topic/VirtualTopic.X | Events |
MQTT path
| ActiveMQ MQTT topic prefix | KubeMQ pattern |
|---|---|
events/<channel> | Events |
store/<channel> | Events Store |
queues/<channel> | Queues |
commands/<channel> | Commands (MQTT 5.0 only) |
queries/<channel> | Queries (MQTT 5.0 only) |
Wildcards + and # are supported for Events subscriptions only.
Security
All three connectors accept the same KubeMQ JWT as the credential, but deliver it differently:
| Connector | Where the JWT goes | Auth disabled |
|---|---|---|
| AMQP 1.0 | SASL PLAIN password field (username is informational) | ANONYMOUS or bare AMQP header accepted |
| STOMP | CONNECT passcode header (username recorded for audit) | Any credentials accepted |
| MQTT | CONNECT password field (username recorded for audit) | Any credentials accepted |
All three connectors are opt-in (Enable = false). They do not open listeners until
explicitly enabled. When Authentication.Enable = false (the server default), listeners accept
unauthenticated clients — enable authentication or firewall the ports when the server is reachable
from untrusted networks.
TLS: each connector uses the server-wide Security block. TLS is active on the TLS port only
when Security is configured. mTLS (client-certificate auth) is available on the AMQP 1.0 path
via SASL EXTERNAL (cert CN = ClientID).
Authorization (Casbin): with Authorization.Enable = true, Write is enforced on SEND /
produce, and Read on SUBSCRIBE / consume, against the resolved KubeMQ channel.
See Authentication & Security and the configuration reference.
What Does NOT Migrate / Deviations
Hard blockers
| Feature | Status | Detail |
|---|---|---|
| OpenWire protocol | ❌ Not supported | See the callout at the top of this page. There is no configuration option to add OpenWire support. |
| Transactions | ❌ Not supported | No SESSION_TRANSACTED / XA (JMS), no STOMP BEGIN / COMMIT / ABORT. Use idempotent producers and at-least-once consumers instead. |
| Message selectors (STOMP path) | ❌ Not supported | The STOMP connector rejects selector headers with ERROR selectors not supported and closes the connection. Remove all selector usage from STOMP applications. |
| No client-settable DLQ | ❌ | No dead-letter address is exposed to clients over AMQP 1.0, STOMP, or MQTT. A message that exceeds MaxReceiveCount is silently dropped — there is no consumable dead-letter address over any of these protocols. |
Behavioral deviations
| Feature | Deviation |
|---|---|
| Selectors (AMQP 1.0 path) | Supported on Events / Events Store only (SQL92 subset via apache.org:selector-filter). Rejected on /queues/ links (amqp:not-implemented). |
| ActiveMQ durable subscriptions | Map to Events Store via /events-store/<name> (AMQP 1.0) or /topic-store/<name> (STOMP). Replay-position headers control where the subscription starts. unsubscribe() / DETACH of the durable identity is node-local — connect back to the same node to cleanly detach. |
| ActiveMQ Virtual Topics | Map to KubeMQ consumer groups via link property x-opt-kubemq-group (AMQP 1.0) or a shared STOMP subscription. No automatic VirtualTopic. prefix translation. |
| Ordering | Per-channel ordering is node-local, not cluster-wide. MQTT ordering is QoS-dependent (QoS 0 unordered; QoS 1/2 ordered per connection only). |
| STOMP reply-to RPC | The reply subscription must be active before the SEND carrying reply-to is issued. Sending without a pre-existing reply subscription produces ERROR reply-to subscription required and closes the connection. |
| MQTT 3.1 rejected | KubeMQ refuses MQTT 3.1 clients at CONNECT. Use MQTT 3.1.1 or 5.0. |
| MQTT retained messages | RetainAvailable = 0. Retained publishes are rejected with an audit event (not silently dropped). |
| MQTT RPC | Request/reply (Commands / Queries) requires MQTT 5.0. Not available over MQTT 3.1.1. |
Verification Smoke Test
Choose the path that matches your application, enable the relevant connector(s), and point a test client at the KubeMQ endpoint. The AMQP 1.0 and MQTT paths defer to their guides for the full client snippet; the STOMP quick check is below.
- AMQP 1.0 path (Java/JMS) — requires the AMQP 1.0 connector enabled
(
CONNECTORS_AMQP10_ENABLE=true). See Migrating from JMS for the full Qpid JMS snippet, and Migrating from AMQP 1.0 for the nativego-amqpsnippet. - MQTT path — requires the MQTT connector enabled (
CONNECTORSMQTT_ENABLE=true). See Migrating from MQTT for the fullpaho-mqttsnippet.
STOMP path — requires the STOMP connector enabled (CONNECTORS_STOMP_ENABLE=true):
# stomp.py 8.x — publish one message, consume it, confirm arrival
# Symbols: stomp.Connection, conn.connect, conn.send, conn.subscribe,
# ConnectionListener.on_message, conn.ack, conn.disconnect
import stomp, time
class Listener(stomp.ConnectionListener):
def __init__(self): self.received = []
def on_message(self, frame):
self.received.append(frame.body)
print(f"received: {frame.body}")
listener = Listener()
conn = stomp.Connection([("kubemq.example.com", 61613)])
conn.set_listener("", listener)
conn.connect(login="user", passcode="<jwt-or-empty>", wait=True)
# Subscribe before publishing (required for Events pattern)
conn.subscribe("/topic/smoke-test", id=1, ack="auto")
# Publish
conn.send("/topic/smoke-test", body="hello from activemq migration")
time.sleep(1)
assert len(listener.received) == 1, "smoke test failed: no message received"
print("smoke test passed")
conn.disconnect()See Also
Migration hub
The connector map, the cross-protocol comparison matrix, and every ecosystem guide.
Migrating from JMS
The primary Java/ActiveMQ path — swap the ConnectionFactory to Apache Qpid JMS over AMQP 1.0.
Migrating from AMQP 1.0
Native AMQP 1.0 (Artemis) clients — address-prefix mapping, a go-amqp example, and RPC.
Migrating from STOMP
STOMP client migration — every destination type maps; the stomp.py snippet and ack modes.
Migrating from MQTT
MQTT client migration — topic-prefix mapping, QoS, retain/RPC caveats, and 3.1.1/5.0 support.
AMQP 1.0 connector reference
Wire contract and known deviations for the AMQP 1.0 connector.
STOMP connector reference
Wire contract, error frames, and ack modes for the STOMP connector.
MQTT connector reference
Topic mapping, QoS, and session behavior for the MQTT connector.
Connector configuration reference
Configuration fields and enable variables for all connectors.
Was this page helpful?
Migration
Pick the right KubeMQ wire-protocol connector for your broker and migrate onto it — the connector map, a cross-protocol matrix, and guides for nine ecosystems.
Migrating from AMQP 1.0
Point a native AMQP 1.0 client at KubeMQ — address-prefix pattern mapping, a go-amqp example, RPC, and the transaction and settlement deviations.