Back to blog

// OSSeva Blog

Migration

Kafka 3 to 4 Upgrade: The Path From a 3.x Cluster to Kafka 4.3

Matt Reynolds10 min read

The short answer

If your Kafka 3.x cluster already runs in KRaft mode with software and metadata version 3.3 or later, it can take a rolling upgrade directly to Kafka 4.x: 4.3 accepts servers from any version 3.3.x through 4.2. If it still runs in ZooKeeper mode, it cannot. Kafka 4.0 removed ZooKeeper, so the cluster first migrates its metadata to KRaft on a 3.x bridge release, and 3.9 is the last one. Our ZooKeeper to KRaft migration runbook covers that step.

Before the brokers move, check four more things: brokers, Connect and the command-line tools need Java 17; clients older than 2.1 stop working (KIP-896); a set of long-deprecated configurations is gone; and broker logging moved to Log4j2. The upgrade ends with kafka-features.sh upgrade, and after that step a metadata downgrade is not supported for 4.0 or 4.3.

Upgrade paths

FromToSupported?
3.3.x to 3.9.x, KRaft mode4.0, 4.1, 4.2 or 4.3Yes, rolling
4.0.x to 4.2.x4.3Yes, rolling
KRaft mode older than 3.34.xNot directly. The Kafka documentation recommends upgrading to 3.9 first
Any 3.x in ZooKeeper mode4.xNo. Migrate to KRaft on a bridge release first; 3.9 is the last bridge release
2.x4.xNo. Upgrade to 3.9 in ZooKeeper mode, migrate to KRaft, then upgrade
4.x, after finalizing3.xOnly if no version in between has metadata changes; 4.0 and 4.3 both do

Aim for 4.3. The Apache Kafka downloads page lists 4.3.1, 4.2.2 and 4.1.2 as supported releases, and 4.0 and every 3.x release under archived releases. For dates, see the Kafka end-of-life chart and Kafka 3.9 end of life.

Pre-upgrade checklist

# 1. Which mode? ZooKeeper mode has zookeeper.connect and no process.roles
grep -E "^(process.roles|zookeeper.connect)" /opt/kafka/config/server.properties

# 2. KRaft only: metadata version must be 3.3-IV3 or later
bin/kafka-features.sh --bootstrap-controller ctrl-1:9093 describe

# 3. Java on every broker, controller and Connect host
java -version

# 4. Clients still using API versions that 4.0 removed (JMX, on each broker)
#    kafka.network:type=RequestMetrics,name=DeprecatedRequestsPerSec,...

# 5. Configuration and tooling that 4.0 removed (see the table below)
grep -rnE "message.format.version|delegation.token.master.key|offsets.commit.required.acks|log.message.timestamp.difference.max.ms|metrics.jmx.(black|white)list|auto.include.jmx.reporter" /opt/kafka/config
grep -rnE -- "--whitelist|--zookeeper|--authorizer-properties|kafka.tools.MirrorMaker|log4j.properties" ./ops ./ansible ./helm

The metric in step 4 is the reliable client check. Let it run across a full business cycle, including month-end jobs, and treat a client that reports no software name as something to investigate. The KIP-896 guide lists the minimum versions of librdkafka, Sarama, KafkaJS and kafka-python.

Breaking change 1: ZooKeeper mode is gone

Kafka 4.0 runs only in KRaft mode. A broker started with zookeeper.connect and no process.roles is a ZooKeeper-mode broker, and there is no 4.x release it can run. The migration happens on 3.x: add a KRaft controller quorum, copy the metadata, restart the brokers into KRaft mode, then finalize. Finalizing the migration is a point of no return, separate from the 4.x upgrade that follows it.

How to detect it: step 1 of the checklist. Also look for tooling that still talks to ZooKeeper, such as scripts that pass --zookeeper, and for the kafka-acls options --authorizer, --authorizer-properties and --zk-tls-config-file, all removed in 4.0. Use --bootstrap-server or --bootstrap-controller instead.

Breaking change 2: Java 17 for servers, Java 11 for clients

From 4.0, brokers, Kafka Connect and the command-line tools require Java 17. Clients and Kafka Streams applications require Java 11, up from Java 8. The 4.3 documentation lists Java 17, 21 and 25 as fully supported, recommends the most recent LTS release, and supports Java 11 only for clients, Streams and related modules. Scala 2.12 support was removed as well.

How to detect it: java -version on every server host, the base image of each container, and the JVM of each Connect worker. A broker that fails on Java 11 fails at startup, so this is easy to find in staging and expensive to find in production.

Breaking change 3: old clients stop working

4.0 removed protocol API versions older than those of Kafka 2.1. Java clients, including Streams and Connect, must be 2.1 or newer before the brokers move to 4.0, and brokers must be 2.1 or newer before the Java clients move to 4.0. The risk is in old non-Java clients and vendor products that embed an old library. The DeprecatedRequestsPerSec metric finds them, and the KIP-896 post covers the details, including why 4.0.1 or later is the release to run rather than 4.0.0.

Breaking change 4: removed and changed configurations

Most of these were deprecated for several releases. A removed setting left in a configuration file no longer does anything, so find each one and decide what replaces it.

Removed in 4.0Use instead
log.message.format.version, message.format.versionNothing; remove them
delegation.token.master.keydelegation.token.secret.key
log.message.timestamp.difference.max.mslog.message.timestamp.before.max.ms and log.message.timestamp.after.max.ms
offsets.commit.required.acksNothing; remove it
metrics.jmx.blacklist, metrics.jmx.whitelistmetrics.jmx.exclude, metrics.jmx.include
auto.include.jmx.reportermetric.reporters, which now defaults to JmxReporter
MirrorMaker 2 topics.blacklist, groups.blacklist, config.properties.blacklisttopics.exclude, groups.exclude, config.properties.exclude

Several defaults changed too, and these alter behaviour without any error:

  • message.timestamp.after.max.ms fell from effectively unlimited to one hour, so with CreateTime timestamps a record stamped more than an hour in the future is rejected. Producers on hosts with bad clocks are the ones to check.
  • The producer's linger.ms default rose from 0 to 5.
  • enable.idempotence no longer falls back quietly when max.in.flight.requests.per.connection is above 5.
  • num.recovery.threads.per.data.dir rose from 1 to 2, and the minimum segment.bytes is now 1 MB.
  • The tiered storage thread pool settings no longer accept -1.

Breaking change 5: Log4j2, MirrorMaker 1 and the tools

  • Logging. Kafka moved from Log4j to Log4j2, and KafkaLog4jAppender was removed. A customised log4j.properties needs converting; the Kafka notes point to the log4j-transform-cli tool. In 4.1 the LogCleaner logger was renamed to org.apache.kafka.storage.internals.log.LogCleaner.
  • MirrorMaker 1 was removed. Replication between clusters moves to the Connect-based MirrorMaker 2.
  • Tools. kafka-console-consumer --whitelist became --include; --bootstrap-server accepts only comma-separated lists; kafka-configs.sh now uses the incremental alter configs API; the separate config/kraft directory was folded into config.
  • Client and Streams APIs. Methods such as poll(long), Admin.alterConfigs and the old partitioner classes were removed, as were Streams APIs deprecated in 3.6 or earlier. Compiling each application against the 4.x client libraries is the fastest way to find them.

4.1 and 4.2 add less. Kafka Streams 4.1.0 has a memory leak in range scans and some DSL operators, so go to 4.1.1 or later if you stop there. Eligible Leader Replicas are on by default for new clusters from 4.1. 4.3 deprecates kafka-streams-scala and group.coordinator.rebalance.protocols ahead of 5.0.

The procedure

  1. ZooKeeper clusters: upgrade to 3.9, migrate to KRaft and finalize the migration, following the runbook. Run in KRaft mode on 3.9 for a while before going further.
  2. KRaft clusters older than 3.3: upgrade to 3.9 first.
  3. Install Java 17 or later on every server, and Java 11 or later wherever Streams and client applications will run 4.x libraries.
  4. Clean the configuration of the removed settings, convert the logging configuration to Log4j2 and move MirrorMaker 1 flows to MirrorMaker 2.
  5. Clear the client inventory until DeprecatedRequestsPerSec reads zero on every broker.
  6. Roll each server one at a time: shut it down, install the 4.3 binaries, start it, and wait for it to rejoin before the next one.
    bin/kafka-metadata-quorum.sh --bootstrap-server broker-1:9092 describe --status
    bin/kafka-topics.sh --bootstrap-server broker-1:9092 --describe --under-replicated-partitions
    Move on only when the quorum is healthy and no partitions are under-replicated.
  7. Verify behaviour and performance with every server on 4.3 and the old metadata version still in force. This is the stage to watch producer latency, consumer lag and the logs.
  8. Finalize when you are satisfied:
    bin/kafka-features.sh --bootstrap-server broker-1:9092 upgrade --release-version 4.3
  9. Upgrade clients to 4.x libraries on their own schedule. Any client from 2.1 onwards already works with 4.3 brokers.

Rollback limits

The finalize step is the line. Every metadata version records whether it contains metadata changes, and a metadata downgrade is only possible when no version between your current and target releases has them. 4.0 and 4.3 both do, so once a cluster is finalized at 4.3 the documentation's answer is that metadata downgrade is not supported. Two further one-way steps sit nearby: finalizing a ZooKeeper to KRaft migration, and the new consumer group protocol from KIP-848, which is enabled when the 4.0 upgrade is finalized and, once a group uses it, limits any downgrade to 3.4.1 or newer.

So take the rollback decision before finalizing. Run every server on 4.3 binaries at the old metadata version long enough to see a full business cycle, keep the previous binaries and configuration staged, and rehearse a binary rollback in staging before production.

Where OSSeva fits

The usual reason a cluster stays on 3.x is the ZooKeeper migration, an embedded client that cannot move, or a platform that pins a Kafka version. OSSeva for Apache Kafka patches the version you run, from 2.8 through 3.x, including 3.8 and 3.9, which upstream has archived, and covers both ZooKeeper-mode and KRaft-mode clusters. Patch covers the broker and client libraries; Assure adds a cluster configuration audit and a throughput and latency review; Operate adds 24/7 broker and consumer-lag monitoring, a 15-minute P1 response and Kafka Streams and Connect operational support. Pricing is per cluster; book a discovery call for a quote. See also Kafka and ZooKeeper extended support.

Frequently asked questions

Can I upgrade Kafka 3.x to 4.0 while still using ZooKeeper?

No. Kafka 4.0 and later run only in KRaft mode. Migrate to KRaft on 3.9, the last bridge release, then upgrade.

Can I upgrade directly from Kafka 3.9 to 4.3?

Yes, if the cluster runs in KRaft mode. 4.3 accepts rolling upgrades from any version 3.3.x through 4.2.

What Java version does Kafka 4 need?

Java 17 for brokers, controllers, Connect and the tools. Java 11 for clients and Kafka Streams. The 4.3 documentation recommends the most recent Java LTS release.

Will Kafka 3.x clients work with Kafka 4 brokers?

Yes, from client version 2.1 onwards. Older Java clients and non-Java clients of similar age fail because 4.0 removed the protocol versions they use.

Can I downgrade from Kafka 4 to 3.9?

Not after finalizing at a metadata version with metadata changes, which includes 4.0 and 4.3. Decide on rollback while the servers run 4.x binaries at the old metadata version.

What does kafka-features.sh upgrade do?

It finalizes the upgrade by raising the cluster's feature levels, including metadata.version, to the new release. Run it only after every server is on the new version and the cluster has been verified.

Tags

Apache KafkaKafka 4UpgradeKRaftJava 17

Ready to get your open source under control?

Talk to an OSSeva engineer about CVE coverage, compliance, and migration support for your stack.