Skip to main content

MirrorMaker 1 Is Gone: How to Migrate Legacy Mirroring to MirrorMaker 2

· 10 min read
OSO Engineering
The team behind OSO Kafka Backup

The original Kafka MirrorMaker (kafka.tools.MirrorMaker, run through the kafka-mirror-maker.sh script) was deprecated in Kafka 3.0.0 under KIP-720 and fully removed in Kafka 4.0.0. If a cluster is still running it, moving that job onto MirrorMaker 2 isn't a config patch — it's a new config file format, a topic-naming decision, and, for the first time, real consumer-offset translation between clusters.

This post is the flag-by-flag migration guide: what changes, what the old options map to, and the order of operations that keeps a rollback path open until the cutover is proven.

Key takeaway

Three things change in the move from MirrorMaker 1 to MirrorMaker 2: the config format goes from two flat properties files to one mm2.properties file, topic names get a source-cluster prefix by default, and consumer group offsets can now translate across clusters instead of resetting. This post maps all three.

Why MirrorMaker 1 is going away

Apache Kafka's KIP-720 deprecated the original MirrorMaker in Kafka 3.0.0, and the Kafka 4.0.0 upgrade notes confirm the follow-through: "The original MirrorMaker (MM1) and related classes were removed. Please use the Connect-based MirrorMaker (MM2)." Kafka 4.0 also dropped several MM1-only settings that have no MM2 equivalent, including use.incremental.alter.configs, add.source.alias.to.metrics, and the legacy blacklist/exclude options on MirrorSourceConnector.

This wasn't a rename. KIP-720's own motivation states plainly that MirrorMaker 2 "is an improvement over the original MirrorMaker when it comes to reliability and functionality for the majority of use cases" — Kafka Connect-based replication had already become the recommended path, and the deprecation-then-removal cycle gave teams, in the KIP's words, "a long time and ample warning to transition away from MM1 at their own pace." That warning period is over as of Kafka 4.0. If you haven't read what MM2 actually is yet, What Is Kafka MirrorMaker? covers the three-connector model and a minimal working config before you go further here; Kafka 4.0: What Changed covers the rest of that release.

What actually changes — the shape of the job

MirrorMaker 1 was a standalone process: one consumer, one producer, wired together in a loop. MirrorMaker 2 is a Kafka Connect application — a worker process (or several) running connector tasks that Connect itself schedules and rebalances. That difference in runtime model drives every other change below.

AspectMirrorMaker 1 (kafka-mirror-maker.sh)MirrorMaker 2 (connect-mirror-maker.sh)
Config formatTwo flat Java properties files (--consumer.config, --producer.config)One mm2.properties file with named cluster aliases
Process modelStandalone consumer-producer loop, one processKafka Connect workers running connector tasks
Topic namingIdentical name on the target clusterSource-prefixed by default ({source}.{topic})
Consumer offsetsNo built-in cross-cluster translationCheckpoint connector translates offsets between clusters
Topic selection--include (Java regex){source}->{target}.topics per replication flow

Nothing in that table is a drop-in flag swap. Migrating means standing up a Connect-based deployment, not editing a properties file in place.

Mapping the old flags to the new config

The legacy tool's flags come straight from kafka.tools.MirrorMaker in the Apache Kafka source (verified against the 3.9.0 tag, the last release line to ship it). Here's where each one lands in MirrorMaker 2:

Old flag (kafka-mirror-maker.sh)What it didMM2 equivalent
--consumer.configEmbedded consumer properties for the source clusterPer-cluster {alias}.bootstrap.servers plus consumer overrides inside mm2.properties
--producer.configEmbedded producer properties for the target clusterPer-cluster {alias}.bootstrap.servers plus producer overrides inside mm2.properties
--include (or the deprecated --whitelist)Java-regex allowlist of topics to mirror{source}->{target}.topics (regex or comma-separated list), scoped to one replication flow
--num.streamsNumber of consumer threads in the one MM1 processtasks.max, MM2's parallelism knob — units of work Kafka Connect distributes across worker processes rather than threads in a single process
--offset.commit.interval.msHow often MM1 committed consumer offsetsInherited from Kafka Connect's own worker offset-flush behavior; not a direct MM2 property
--abort.on.send.failureWhether MM1 exited on a failed produceConnect producer error handling (errors.tolerance and retry configuration) on the underlying Connect producer
--message.handlerCustom per-record transformation classNo direct equivalent — rebuild the logic as a Kafka Connect Single Message Transform

That last row is worth calling out on its own: if a migration relied on --message.handler for custom record logic, there's nothing to carry over mechanically. It has to be re-implemented as a Connect transform before cutover, not discovered as a gap afterward. For the full minimal two-cluster mm2.properties example and what tasks.max actually governs underneath the connectors, see What Is Kafka MirrorMaker? and Kafka MirrorMaker 2 Architecture.

The topic-naming decision you have to make before cutover

This is the change most migrations trip over. MirrorMaker 1 wrote to a target topic with the exact same name as the source — there was no renaming step in the tool at all. MirrorMaker 2's default DefaultReplicationPolicy behaves differently: per Apache Kafka's geo-replication documentation, "the names of replicated topics in the target clusters have the format {source}.{source_topic_name}." A topic named orders on the source shows up as primary.orders on the target by default, not orders.

If consumers on the target side already expect the unprefixed name — because that's what MirrorMaker 1 always gave them — set:

replication.policy.class=org.apache.kafka.connect.mirror.IdentityReplicationPolicy

IdentityReplicationPolicy keeps the destination topic name identical to the source, matching MM1's old behavior. But it isn't risk-free: MirrorMaker 2 also uses that source-prefix as the marker it checks to avoid mirroring a topic back onto itself in a loop. Remove the prefix and you remove that built-in tell, so review replication flow directions and topic filters carefully before enabling identity naming — especially in any topology with flows running in both directions between the same pair of clusters.

Whichever policy you choose, decide it before the first record replicates. It determines whether downstream consumers need a subscription change on cutover day or not.

Consumer offsets finally get a real answer

MirrorMaker 1 had no built-in mechanism to translate a consumer group's committed offsets from the source cluster into equivalent offsets on the target. Teams migrating consumers under MM1 typically accepted an offset reset — restarting from earliest or latest and living with the duplicate or skipped records that followed.

MirrorMaker 2 closes that gap with its MirrorCheckpointConnector, which maps each consumer group's source offset to the correct position on the target cluster. This is a genuine capability upgrade, not just something to route around: plan the migration to actually consume from the translated checkpoint rather than re-seeding consumers from scratch. The full mechanics — the checkpoints and offset-syncs topics, the translation flow, and where it can fail — are covered in MirrorMaker 2 Offset Sync.

Migration checklist

  1. Inventory every kafka-mirror-maker.sh invocation currently running, along with its --consumer.config and --producer.config property files.
  2. Decide DefaultReplicationPolicy vs IdentityReplicationPolicy using the topic-naming section above — this affects every downstream consumer.
  3. Build the equivalent mm2.properties using the flag-mapping table, including cluster aliases, {source}->{target}.topics, and tasks.max.
  4. Start MirrorMaker 2 alongside the still-running MirrorMaker 1 process, pointed at the same clusters, and verify records land correctly before touching production consumer traffic.
  5. Cut consumers over using MM2's checkpoint topics, not a blind offset reset, so groups resume from a translated position instead of from scratch.
  6. Decommission the kafka-mirror-maker.sh process — its systemd unit, cron entry, or supervisor config — only once MirrorMaker 2 has run cleanly through at least one full monitoring cycle.

Keep the old MM1 process definition around, even stopped, until MM2 has proven itself. Stopping it is reversible right up until its config is deleted for good — that's the rollback boundary for this migration.

What migrating to MM2 does not give you

MirrorMaker 2 is a better live mirror than MirrorMaker 1 ever was — but it is still a live mirror. A corrupted record or a mistaken delete replicates through the checkpoint connector exactly as faithfully as good data does.

OSO Kafka Backup writes topic data and consumer group offsets to S3, S3-compatible storage, Azure Blob, GCS, or a filesystem, independently of any live replication path, with point-in-time recovery at millisecond precision. That's worth doing alongside a MirrorMaker migration, not instead of it — a cutover is exactly the kind of high-blast-radius change where an independent, restorable copy earns its keep.

Migrating mirrors? Back up first

A MirrorMaker cutover is a planned, high-blast-radius change to your replication path. OSO Kafka Backup keeps an independent, point-in-time copy of topics and consumer offsets so a bad cutover isn't the only copy of the truth. See the disaster recovery use case for where it fits.

The migration in one paragraph

MirrorMaker 1 is gone as of Kafka 4.0 — deprecated in 3.0 under KIP-720, removed for good in 4.0.0. Moving to MirrorMaker 2 means trading two flat properties files for one mm2.properties, choosing between the default source-prefixed topic names and IdentityReplicationPolicy for MM1-style naming, and — for the first time — getting real consumer-offset translation through the checkpoint connector instead of a reset. Run both mirrors side by side, cut consumers over on the translated checkpoint, and only then retire the legacy process.

Frequently asked questions

When was MirrorMaker 1 removed from Apache Kafka?

It was deprecated in Kafka 3.0.0 under KIP-720 and fully removed in Kafka 4.0.0. The Kafka 4.0 upgrade notes state that "the original MirrorMaker (MM1) and related classes were removed" in favor of the Connect-based MirrorMaker 2.

Can I convert my kafka-mirror-maker.sh config directly to mm2.properties?

Not as a straight flag swap. MirrorMaker 1’s separate consumer.config and producer.config files map to per-cluster settings inside one mm2.properties file, and its --include topic regex becomes a per-flow topics setting, but the underlying process model changes from a standalone consumer-producer loop to Kafka Connect workers and tasks.

Will MirrorMaker 2 replicate topics under the same name as MirrorMaker 1 did?

Not by default. MirrorMaker 2’s DefaultReplicationPolicy prefixes replicated topics with the source cluster alias, so to match MirrorMaker 1’s unprefixed behavior you need to set replication.policy.class to IdentityReplicationPolicy.

Does migrating from MirrorMaker 1 to MirrorMaker 2 preserve consumer group offsets?

MirrorMaker 2 can translate consumer group offsets between clusters using its checkpoint connector, which MirrorMaker 1 never had. Migrating consumers under MirrorMaker 1 typically meant accepting an offset reset instead.

Can I run MirrorMaker 1 and MirrorMaker 2 at the same time during migration?

Yes. Running MirrorMaker 2 alongside a still-active MirrorMaker 1 process against the same clusters is the safest way to validate the new configuration before cutting consumers over and decommissioning the legacy process.