Back to blog

OSSeva Blog

Migration

Migrating ActiveMQ Classic to Artemis: What Actually Changes

Randall McClureUpdated 13 min read

The short answer

To migrate ActiveMQ Classic 5.x to Artemis, build an Artemis broker with an OpenWire acceptor, translate destinations, security and virtual topics, test behaviour rather than connections, move or drain the KahaDB store, then switch clients. Existing OpenWire JMS clients can stay as they are. The store, configuration, monitoring and broker topology do not carry over.

Not migrating yet? Classic extended support and the Artemis path keeps the 5.x line patched while the store and topology questions are settled.

Running ActiveMQ Artemis in production? OSSeva patches and supports it, end-of-life versions included.

Migration steps

The order below follows the Apache Artemis migration guide, which assumes a working Classic 5.x broker with OpenWire JMS clients and replaces the broker while leaving the clients intact.

  1. Inventory the Classic configuration. Count network connectors, virtual destinations, policy entries and custom plugins in conf/activemq.xml (commands in the inventory section below). Each non-zero count is a work item.
  2. Create an Artemis broker instance. Unlike Classic, Artemis needs an explicit instance: bin/artemis create --user <user> --password <password> --role admins /opt/artemis, then bin/artemis run for the foreground or bin/artemis-service start as a service. Configuration lives in etc/broker.xml, the store in data, logs in log. By default Artemis starts an OpenWire connector on the same port as Classic, 61616, so existing clients can connect straight away.
  3. Turn transport connectors into acceptors. Classic’s <transportConnector> entries become <acceptor> entries in etc/broker.xml. One Artemis acceptor can serve several protocols on one port, restricted with protocols=, for example tcp://0.0.0.0:61616?protocols=OPENWIRE. Artemis has no separate nio or ws transport: it is non-blocking throughout, and the TCP acceptor detects WebSocket clients.
  4. Turn destinations into addresses. A Classic queue becomes an address with <anycast> routing and a queue of the same name; a topic becomes an address with <multicast> routing. Both brokers can auto-create destinations that clients request, so predefine only the ones you need to.
  5. Port authentication, authorization and TLS. JAAS user and group files are interchangeable: users.properties and groups.properties map to artemis-users.properties and artemis-roles.properties, and Classic groups are called roles in Artemis. Classic’s Simple Authentication Plugin has no Artemis equivalent and must move to JAAS first. authorizationEntry rules become <security-setting> permissions, and both brokers use the JDK’s JSSE for TLS.
  6. Handle virtual topics. Set virtualTopicConsumerWildcards on the OpenWire acceptor so that Consumer.A.VirtualTopic.Orders maps to the Artemis queue VirtualTopic.Orders::Consumer.A.VirtualTopic.Orders. Or change consumers to the JMS 2.0 shared subscription API or to the fully qualified queue name. Details below.
  7. Test behaviour, not connectivity. Redelivery and dead-letter handling, transactions, selectors, durable subscriptions, virtual topics, advisory-message consumers and slow consumers. A successful OpenWire connection proves only that the wire protocol matches.
  8. Move the messages. KahaDB and the Artemis journal are not interchangeable. Either drain the queues (stop producers, let consumers empty them, switch), or export the store with the Apache ActiveMQ Command Line Tools and import it into the running Artemis broker (commands below).
  9. Rebuild monitoring, then cut over. Re-point dashboards and alerts at the Artemis management model before the switch, then move clients by changing the broker URL. Keep Classic available until its queues are empty and the rollback window closes.
  10. Move clients off OpenWire later, if at all. Moving to the Artemis Core client or AMQP is a separate, optional project. Do not bundle it.

Compatibility table: what carries over and what does not

AreaActiveMQ ClassicActiveMQ ArtemisWhat to do
OpenWireNative protocolAccepted with protocols=OPENWIRE. Artemis documents compatibility with the OpenWire client library from ActiveMQ 5.12.x or higherKeep OpenWire clients unchanged for cutover. Test any client older than 5.12 before you rely on it
STOMPDefault stomp connector on port 61613STOMP 1.0, 1.1 and 1.2 with protocols=STOMPRe-create the acceptor; test heartbeats and subscription acknowledgements
AMQPAMQP 1.0, available from Classic 5.8AMQP 1.0 with protocols=AMQPRe-create the acceptor; any AMQP 1.0 client can connect, but verify address and queue naming
MQTTDefault mqtt connector on port 1883MQTT 3.1, 3.1.1 and 5 with protocols=MQTTRe-create the acceptor; check retained messages and session handling
WebSocketSeparate ws transportHandled by the TCP acceptorRemove the separate listener, test through your proxy
JMS API5.19.x broker: javax JMS 1.1; the 5.19.x client also supports Jakarta JMS 2. 6.x: Jakarta JMS 2 and 3.1 (partial) on the brokerArtemis lists “Full Jakarta Messaging 3.1, JMS 2.0 & 1.1 support”, with separate javax and Jakarta client variantsPick the client variant that matches your javax.jms or jakarta.jms imports. JMS 2.0 shared subscriptions are available
Message storeKahaDB or mKahaDB: journal plus indexAppend-only journal, no index; messages paged on the producer sideNot interchangeable. Drain, or export to Artemis XML and import
Configurationconf/activemq.xml; instance optionaletc/broker.xml; instance created with bin/artemis createTranslate by hand; there is no automatic converter in the migration guide
DestinationsQueues and topicsAddresses with anycast or multicast routingMap every predefined destination and policy entry
Virtual topicsVirtualTopic.* with Consumer.*. queuesNot on by default. virtualTopicConsumerWildcards, JMS 2.0 shared subscriptions or a fully qualified queue nameHighest risk of silent breakage; test every consumer
Users and groupsJAAS or Simple Authentication PluginJAAS only; groups are called rolesCopy the properties files; move off the Simple plugin first
Network of brokersStore-and-forward network connectorsClustering and bridges, designed differentlyRedesign the topology rather than translate it

Moving the store: export from KahaDB, import into Artemis

Artemis supports an XML format for message store exchange. The Apache ActiveMQ Command Line Tools include an export tool that writes a KahaDB or MultiKahaDB store out as Artemis XML. It can filter by queue and topic pattern, which suits migrations where only some data matters:

# Export the whole store
./bin/export kahadb --source /path/to/kahadb/ --target /path/to/output.xml

# Export only queues matching a pattern, and map virtual topic consumer queues
./bin/export kahadb --qp "orders.>" --source /path/to/kahadb/ --target /path/to/output.xml   --virtualTopicConsumerWildcards "Consumer.*.>;2"

The tool’s README documents these options and that the output can be imported with the Artemis CLI. The Artemis data tools documentation describes artemis data imp as importing the file “to a running broker”, with --input, --host, --port, --user and --password options. Run the export against a copy of the Classic data directory and the import against a test Artemis broker first, then compare queue depths. The tool’s latest release listed in its README is 0.2.0, from July 2020, so test it against your Classic version rather than assuming it handles a newer store.

Why this is a replacement, not an upgrade

The most common misunderstanding in this migration is in its framing. ActiveMQ Classic 5.x and ActiveMQ Artemis are separate codebases, and since November 2025 Artemis has been its own Apache top-level project. Artemis is not the next version of Classic — Classic has its own next version, 6.x, and both are maintained. Moving from Classic to Artemis is a broker replacement that happens to keep the brand.

That matters for planning, because “upgrade” and “replace” get very different budgets.

What is genuinely compatible

Start with the good news, because it is real. Artemis speaks OpenWire, the native protocol of Classic. Existing JMS clients built on the activemq-client library can connect to an Artemis broker through an OpenWire acceptor without being recompiled. For a first proof of concept this works almost embarrassingly well.

It is also the trap. A client connecting successfully tells you the wire protocol is compatible. It tells you nothing about whether destinations, persistence, redelivery, advisory messages or your network-of-brokers topology behave the same way. They do not.

The differences that define the project

These come from the Artemis project's own migration documentation.

AreaActiveMQ ClassicActiveMQ Artemis
IO layerSeveral transport implementations — tcp (synchronous), nio (non-blocking)Netty throughout
Message storeKahaDB: a message journal plus an indexAppend-only message journal, no separate index
Configurationconf/activemq.xmletc/broker.xml
DestinationsQueues and topics, declared under <destinations>Addresses with routing types, declared under <addresses>
Queue semanticsQueueAddress with anycast routing
Topic semanticsTopicAddress with multicast routing

The addressing model is the conceptual shift

Classic has queues and topics as first-class, distinct things. Artemis has addresses, and an address has a routing type: anycast delivers each message to one consumer (queue behaviour), multicast delivers to all subscribers (topic behaviour). JMS clients still see queues and topics, because Artemis maps them. But configuration, security settings, address settings and monitoring are all expressed in the address model, so everyone who operates the broker has to learn it even if no developer does.

The store does not carry over

KahaDB and the Artemis journal are different formats. Messages sitting in a Classic store on cutover day are not readable by Artemis. The project provides a route: the ActiveMQ command-line tools include an exporter that writes a KahaDB or mKahaDB store out in Artemis's XML format, for import on the other side.

The choice this gives you:

  • Drain, then cut over. Stop producers, let consumers empty the queues, switch. Simplest, and right for most estates — if your queues actually drain.
  • Export and import. For queues that hold messages for long periods, or DLQs you are obliged to keep.
  • Run both and bridge. Longer transition, no big-bang, more moving parts.

Virtual topics need explicit handling

If you use Classic's virtual topics — producers publish to VirtualTopic.Orders, consumers read from Consumer.A.VirtualTopic.Orders — this is the item most likely to break silently. Artemis can emulate the pattern, but only when told to: the OpenWire acceptor takes a virtualTopicConsumerWildcards option that maps the consumer-queue naming convention onto Artemis addresses. From version 0.2.0 the export tool also understands virtual topic consumer queue mapping, so existing consumers can resume on Artemis without message loss. Neither happens by default.

<!-- etc/broker.xml: OpenWire acceptor with virtual topic mapping -->
<acceptor name="openwire">
  tcp://0.0.0.0:61616?protocols=OPENWIRE;virtualTopicConsumerWildcards=Consumer.*.%3E%3B2
</acceptor>

What to inventory before you estimate

  • Network of brokers. Classic's store-and-forward networks have no direct equivalent. Artemis clusters and bridges solve the same problems differently, and the topology has to be redesigned rather than translated.
  • Advisory messages. Applications that subscribe to ActiveMQ.Advisory.* topics for connection or consumer events depend on Classic behaviour.
  • Destination policies. Per-destination policy entries — memory limits, dead-letter strategies, slow-consumer handling — become address settings, with different names and sometimes different semantics.
  • Plugins and interceptors. Custom broker plugins are Classic API. They are rewritten, not ported.
  • JMX and monitoring. MBean names and structure differ, so dashboards and alerts built on Classic's JMX tree stop working.
  • Selectors and message groups are supported on both, but verify behaviour under your actual load rather than assuming.
# What is this broker actually using? Start here.
grep -cE '<networkConnector' conf/activemq.xml          # network of brokers
grep -cE 'VirtualTopic|virtualDestinations' conf/activemq.xml
grep -cE '<policyEntry' conf/activemq.xml               # destination policies
grep -cE '<plugins>|<bean ' conf/activemq.xml          # custom plugins

While you plan

This is a project measured in quarters for any estate with a network of brokers or custom plugins. Meanwhile, Apache’s Classic download page marks only 5.19.x, 6.3.x and 6.4.x as active and states that inactive versions do not receive updates. That leaves 5.18 and earlier, and 6.0 to 6.2, without fixes. CVE-2023-46604, the OpenWire remote code execution flaw, was fixed in 5.15.16, 5.16.7, 5.17.6 and 5.18.3 according to its CVE record, and brokers that never took those releases are the installed base it was exploited against.

OSSeva backports security fixes onto the 5.x line you run, so the migration can be designed properly. We also cover Artemis and RabbitMQ, so the question of which broker you should land on gets an answer based on your workload rather than on which one we happen to sell.

Related

Sources

All checked on 28 October 2026.

Tags

ActiveMQArtemisMigrationJMS

Get a quote

Ready to get your open source under control?

Tell us what you run. An OSSeva engineer replies within 1 business day with CVE coverage and a price for your stack.

Only your email is required · An engineer replies within 1 business day · No commitment

Prefer to talk or read more first?

Book a call