// OSSeva Blog
MigrationUpgrading Apache Pulsar 3.0 LTS to 4.0 LTS: Path, Breaking Changes, Order and Rollback
The short answer
Pulsar 3.0 LTS reached the end of security support on 2 May 2026, and 3.0.17 was its last release. The release policy supports a live upgrade from one LTS to the next, so a 3.0 cluster can go straight to 4.0 without stopping at 3.1, 3.2 or 3.3. The same policy lists 3.0 to 4.0 and back to 3.0 as a supported round trip, which gives you a rollback path as long as you test it first.
Patch levels matter. Move every component to 3.0.17 before the upgrade, then go to the latest 4.0 release, which is 4.0.13 from 3 August 2026. The project's 4.0 announcement warns that a downgrade often fails when the upgrade started from an older patch than the latest one in its series.
The order is bookies, then brokers, then proxies, then clients. The upgrade guide treats ZooKeeper as optional. Plan a Java 21 runtime for brokers, Functions and IO connectors, and expect a handful of changed defaults.
4.0 has its own clock. Active support ends on 21 October 2026 and security support on 21 October 2027, as the Pulsar 4.0 end-of-life page sets out. This upgrade buys about a year of security fixes before the move to 5.0.
Where the release lines stand on 5 October 2026
| Line | Released | Active support | Security support | Latest |
|---|---|---|---|---|
| 3.0 LTS | 2 May 2023 | Ended 2 May 2025 | Ended 2 May 2026 | 3.0.17 |
| 3.3 | 5 Jun 2024 | Ended 5 Dec 2024 | Ended 5 Dec 2024 | 3.3.9 |
| 4.0 LTS | 21 Oct 2024 | Ends 21 Oct 2026 | Ends 21 Oct 2027 | 4.0.13 |
| 4.1 | 8 Sep 2025 | Ended 8 Mar 2026 | Ended 8 Mar 2026 | 4.1.3 |
| 4.2 | 24 Mar 2026 | Ended 24 Sep 2026 | Ended 24 Sep 2026 | 4.2.4 |
| 5.0 | Milestones only (5.0.0-M2, 12 Sep 2026). The project says milestones are not for production. | |||
Dates come from the Pulsar release policy page. 4.0 is the only line with any upstream support after 24 September 2026, so it is the only sensible target today. The full chart is on the Pulsar end-of-life tracker.
Is 3.0 to 4.0 a supported jump?
Yes. The policy reads "Starting from version 3.0, live upgrade/downgrade between one LTS and the next one is supported", and gives "3.0 -> 4.0 -> 3.0 is OK" as an example. Before 3.0, upgrades had to pass through every feature release, which is why a 2.10 cluster must reach 3.0 first. The 4.0 announcement says users should be on 3.0.x or 3.3.x before upgrading to 4.0, so 3.3 is an alternative starting point, not a required stop. It has been out of support since December 2024 anyway.
The policy also says the project gives no guarantee for any particular configuration, and that each operator should test the upgrade and the downgrade in staging. Treat the rollback path as something to rehearse.
Java and container image changes
| Component | Pulsar 3.0 | Pulsar 4.0 |
|---|---|---|
| Broker, bookie, proxy | Java 17 | Java 21 |
| Functions and IO connectors | Java 17 | Java 21 |
| CLI tools | Java 17 | Java 17 or 21 |
| Java client | Java 8, 11 or 17 | Java 8, 11, 17 or 21 |
| Official Docker image | Ubuntu 22.04 with Temurin 17 | Alpine with Amazon Corretto 21 |
The 4.0 getting-started documentation states that Java 21 is required for Pulsar 4.0, and the project's runtime table lists Java 21 for brokers, Functions and IO connectors from 3.3 onwards. The source build still compiles broker code for Java 17, but running 4.0 servers on 17 is outside what the documentation describes, so move the JVM in the same project. The README also recommends recent patch releases of Java 17 and 21 because of a JVM bug, JDK-8351933, fixed in 17.0.17 and 21.0.8.
The image change catches teams that build on top of apachepulsar/pulsar. The 4.0 images are based on Alpine (PIP-324, introduced in 3.3), so a derived Dockerfile that runs apt-get fails and needs apk instead. The image still runs as user ID 10000. Check anything you install into the image, such as custom connectors with native libraries, against musl rather than glibc.
Breaking and behaviour changes between 3.0 and 4.0
Because the jump crosses 3.1, 3.2 and 3.3 as well as 4.0, read the release notes for all four. These are the changes most likely to affect a running cluster.
| Since | Change | What to do |
|---|---|---|
| 3.2 | Rate limiting rewritten around a token bucket (PIP-322). The separate "precise" publish rate limiter is gone, along with preciseTopicPublishRateLimiterEnable. | Remove the setting. Re-test any producer and dispatch rate limits you rely on under load. |
| 3.2 | Topic compaction no longer keeps messages that have no key (PIP-318). topicCompactionRetainNullKey defaults to false; 3.0 defaults to true. | If readers of compacted topics expect null-key messages, set it to true. |
| 3.3 | CLI tools moved from JCommander to picocli (PIP-343). | Run every script that calls pulsar-admin, pulsar-client or pulsar-perf against a 4.0 test cluster. |
| 4.0 | New Key_Shared implementation with draining hashes (PIP-379), and a new Shared implementation. | Test ordering-sensitive consumers. The dynamic settings subscriptionKeySharedUseClassicPersistentImplementation and subscriptionSharedUseClassicPersistentImplementation switch back to the pre-4.0 code if you need time. |
| 4.0 | loadBalancerMemoryResourceWeight and loadBalancerDirectMemoryResourceWeight default to 0 instead of 1.0. | Expect different bundle placement with the modular load manager. Set the old values if you depend on them. |
| 4.0 | maxMessageSizeCheckIntervalInSeconds removed. The misspelled loadBalancerBandwithInResourceWeight and ...OutResourceWeight are deprecated in favour of loadBalancerBandwidth...; the old names are still read. | Clean up broker.conf. |
| 4.0 | BookKeeper client reorders read sequences by default (bookkeeperClientReorderReadSequenceEnabled=true), following BookKeeper 4.17. | No action for most clusters. Note it when comparing read latency. |
| 4.0 | The built-in Java serialization JavaSerDe for Functions removed, because of deserialization risk. | Move affected functions to a Pulsar schema or your own SerDe before the upgrade. |
| 4.0 | The pulsar-client-1x and pulsar-client-2x-shaded compatibility modules and hdfs2 offloader support dropped. | Replace any 1.x API usage. Use the Hadoop 3 offloader. |
| 4.0.10 | Jetty upgraded from 9.4 to 12.1. The AdditionalServlet plugin interface changed, pulsar-client-auth-athenz needs Java 17, and the default Prometheus metrics provider classes for BookKeeper and ZooKeeper moved. | Rebuild custom servlet plugins. If you carry old config files, set statsProviderClass in bookkeeper.conf to org.apache.pulsar.metrics.prometheus.bookkeeper.PrometheusMetricsProvider and metricsProvider.className in zookeeper.conf to org.apache.pulsar.metrics.prometheus.zookeeper.PrometheusMetricsProvider. Helm chart users before 4.6.0 set bookie.configData.statsProviderClass. |
The default changes only reach you if you take the 4.0 configuration files. The upgrade guide says to upgrade "the binary and configuration files" on each node. Start from the 4.0 files and port your own settings across, rather than copying 3.0 files over, and diff the result so every changed default is a decision rather than an accident.
Clients
The 4.0 announcement states that older Pulsar clients work with Pulsar 4.0 and that the 4.0 Java client works with older clusters. That lets you upgrade the cluster first and clients afterwards, which is the order the upgrade guide gives. The Java client still runs on Java 8.
Do not leave old Java clients in place for long. CVE-2024-47561, a critical code execution flaw in Avro schema parsing, affects Pulsar Java clients before 3.0.7, 3.3.2 and 4.0.0. The project recommends the Pulsar BOM in Maven and Gradle builds, because misaligned client module versions are a common upgrade problem.
BookKeeper, ZooKeeper and the metadata store
- BookKeeper moves from 4.16.7 (bundled with 3.0.17) to 4.17.3 (bundled with 4.0.13). The BookKeeper 4.17.0 release notes say there are no breaking changes, though some defaults differ.
- ZooKeeper is 3.9.5 in both 3.0.17 and 4.0.13, so a cluster on Pulsar's bundled ZooKeeper at 3.0.17 sees no ZooKeeper version change. 3.0.0 shipped with 3.8.1, which is one more reason to reach 3.0.17 first. If you run a separate, older ensemble, upgrade it on its own schedule; our ZooKeeper rolling upgrade guide covers that.
- Oxia became available as a metadata store plugin in 3.3 (PIP-335). Changing the metadata store is a separate project. Keep ZooKeeper through this upgrade, and through the rollback window.
More on how Pulsar uses ZooKeeper is on Pulsar and ZooKeeper.
Rolling upgrade order
- Back up configuration for every component, and record topic stats, backlog and consumer counts for the busiest namespaces.
- Bring everything to 3.0.17: bookies, brokers, proxies and function workers. Run there long enough to trust it.
- ZooKeeper, if you are changing it at all. One server at a time, checking with
pulsar zookeeper-shellafter each. The guide marks this step optional. - Bookies. Disable autorecovery with
bin/bookkeeper shell autorecovery -disable. Canary one bookie: stop it, swap binaries and config, start it withbin/pulsar bookie --readOnly, then restart it in read-write mode once reads look healthy. Roll the rest one at a time, or rack by rack with a rack-aware placement policy. Re-enable autorecovery withbin/bookkeeper shell autorecovery -enable. - Brokers. Canary one, then roll the rest, singly or in batches that leave enough capacity. Check each with
pulsar-admin brokers healthcheckorGET /admin/v2/brokers/health. - Proxies, the same way.
- Function workers. Workers that run inside brokers move with them. The guide gives no order for a separate worker cluster; we upgrade it after the brokers, canary first, and redeploy any function that used
JavaSerDe. - Clients, last, aligned through the BOM.
With geo-replication, the guide says to upgrade one data center and verify it before the others.
Test plan
- Rehearse the whole sequence in staging with production configuration files, then rehearse the downgrade.
- Produce and consume on every subscription type in use. For Key_Shared, check per-key ordering across consumer restarts and scale-outs, and watch the new troubleshooting fields in topic stats.
- Re-run rate limit, quota and backlog policy tests under load.
- Read every compacted topic and confirm null-key handling matches what consumers expect.
- Run each Function and IO connector on the Java 21 runtime, including connectors with native code on Alpine.
- Run admin scripts and automation against the 4.0 CLI.
- Exercise authentication and authorization on brokers and proxies, including any custom servlet or auth plugin after Jetty 12.
- Check that Prometheus still scrapes bookie and ZooKeeper metrics, and that dashboards still find their series.
- Trigger tiered storage offload and read offloaded data back.
- Stop a bookie and a broker under load and watch autorecovery and bundle reassignment.
Rollback
- During a canary, the guide's advice is simple: stop the node, revert binary and configuration, restart it.
- After a full roll, the release policy supports going from 4.0 back to 3.0. We roll back in reverse order, proxies and brokers first and bookies last, so bookies stay on the version they last wrote with until the brokers are settled. Keep 3.0.17 packages, images and configuration files ready on every node.
- Do not adopt post-3.0 features until the rollback window closes. That includes the Oxia metadata store, namespace-level allowed clusters (PIP-321) and new subscription or rate limiting settings that 3.0 does not understand.
- Clients do not need to roll back with the cluster, since old and new clients work across both versions.
If you cannot upgrade yet
A Pulsar upgrade touches three layers and every client team, and a 3.0 cluster that cannot move before the next audit is common. OSSeva ships patched, signed Pulsar builds for 2.10, 2.11, 3.0, 3.1, 3.2 and 4.0, with the ZooKeeper under them covered in the same subscription and CVE notifications when a new advisory affects your version. Builds come as Docker images and Helm charts. Assure adds a multi-tenant namespace isolation audit, a JWT and TLS authentication review, a geo-replication security review and a SOC 2 and HIPAA attestation package. Operate adds 24/7 monitoring of brokers, bookies and ZooKeeper, backlog and consumer lag alerting, a 15-minute P1 response and a named senior Pulsar engineer, with Functions and IO connectors in scope. See Pulsar extended support, Apache Pulsar support, the Pulsar 3.0 end-of-life page and Pulsar production support.
Common questions
Can I upgrade Pulsar 3.0 directly to 4.0?
Yes. From 3.0 onwards the release policy supports live upgrade and downgrade between consecutive LTS lines. Start from 3.0.17 and go to the latest 4.0 release.
Do I have to stop at 3.3?
No. The 4.0 announcement lists 3.0.x or 3.3.x as starting points. 3.3 has been out of support since 5 December 2024.
Does Pulsar 4.0 need Java 21?
The 4.0 documentation says Java 21 is required, and the official images ship it. Java clients still run on Java 8 or later.
Can I upgrade 3.0 straight to 5.0 later?
No. The policy only covers one LTS to the next, and gives "3.2 -> 5.0 is not OK" as an example. Plan 3.0 to 4.0, then 4.0 to 5.0 once 5.0.0 ships.
Tags
Related articles
Ready to get your open source under control?
Talk to an OSSeva engineer about CVE coverage, compliance, and migration support for your stack.