JusDB
Free DB Audit
NoSQL Databases

MongoDB 9.0: What Changed and How to Upgrade from 8.0

Plan a MongoDB 8.0 to 9.0 upgrade: the behavior changes to test, driver minimums, the rolling order for replica sets and sharded clusters, and how far FCV lets you roll back.

JusDB Team
Published October 15, 2026
Updated November 9, 2026
18 min read

MongoDB 9.0.0 shipped on 28 September 2026, and the self-managed packages are now at 9.0.4. From 8.0, the upgrade is the familiar rolling binary swap plus setFeatureCompatibilityVersion. The new part is what applications meet afterwards. A query that used to run with unbounded memory can now fail with ExceededMemoryLimit. A burst of open transactions can hit TooManyOpenTransactions. A change stream pinned to the primary returns InterruptedDueToReplStateChange after an election. An 8.0 cluster also skips three minor releases (8.1, 8.2, and 8.3), whose compatibility changes it has never run. This guide covers what to test, the upgrade order, and how far you can roll back once the feature compatibility version (FCV) is raised.

TL;DR
  • Only an 8.0 deployment at FCV "8.0" (or an 8.3 deployment) can upgrade to 9.0. A 7.0 deployment moves to the latest 8.0 patch first.
  • Target 9.0.4 or later. It carries security fixes and the fix for a shard step-up hang (SERVER-133518) that affects 9.0.0 to 9.0.2.
  • Replica sets: secondaries one at a time, step down the primary, then upgrade it. Sharded clusters: balancer off, config servers, shards, mongos, balancer on.
  • Run the 9.0 binaries at FCV "8.0" for a burn-in period. Raising FCV to "9.0" is the point after which a downgrade needs extra work, and on Atlas it is not possible unless FCV was pinned.
  • Check every driver and ODM against MongoDB's compatibility tables before the binaries change, and stop calling Mongoose syncIndexes() at startup until you run a fixed Mongoose version.

Scope and review date: November 2026. This post covers self-managed MongoDB 8.0 replica sets and sharded clusters moving to MongoDB 9.0, with notes for MongoDB Atlas. Commands, defaults, and version numbers were checked against MongoDB's documentation on 9 November 2026. They were not run in a lab, so rehearse them on staging.


Which MongoDB 9.0 release should you install?

The MongoDB 9.0 release notes list 9.0.0, 9.0.1, and 9.0.2 all dated 28 September 2026. 9.0.4 followed on 13 October 2026 with five CVE fixes and the fix for SERVER-133518, a shard step-up hang. The release notes list 9.0.7 as upcoming, and the Linux install pages currently reference 9.0.4 packages.

Start at 9.0.4 or the newest patch on the day you upgrade, and read the known issues table first. As of November 2026, three issues are open in every 9.0 release, and two need action before the upgrade (both covered below).

javascript
// mongosh, connected to each member in turn
db.version()

Interpretation: this returns the binary version of the connected member, such as 8.0.x. Record it for every mongod and mongos; the procedure does not finish until all members run.

The release model also changed. From 9.0, minor releases go only to Atlas clusters on auto upgrades; self-managed deployments get majors plus an annual Feature Update release numbered x.5 (MongoDB Versions and Upgrade Paths). There is no deadline pressure: MongoDB states that 8.0 reaches end of life in October 2029.

About the performance numbers

MongoDB's launch announcement reports up to 35% faster find-one and 30% faster update-one queries in its own benchmarks against 8.0. Measure your own workload before planning capacity around vendor figures.

Can you upgrade to MongoDB 9.0 directly from 7.0 or 8.0?

From 8.0, yes. From 7.0, no. The 8.0 to 9.0 replica set procedure says you must run an 8.0 or 8.3 release. A 7.0 deployment first upgrades every member to the latest 8.0 patch, raises FCV to "8.0", and only then starts the 9.0 procedure.

Every member must be running at FCV "8.0", and none may be in ROLLBACK or RECOVERING. On a sharded cluster with access control, check shard members as a shard local user.

javascript
// If any member still reports "7.0", raise FCV first.
// Replica set: run on the primary. Sharded cluster: run on a mongos.
db.adminCommand( { setFeatureCompatibilityVersion: "8.0", confirm: true } )

Interpretation: this applies only to a deployment upgraded from 7.0 that never had FCV raised. It needs a majority of data-bearing members, and fails without confirm: true.

Checking FCV before the 9.0 upgrade

Output from the MongoDB 8.0 to 9.0 upgrade procedure: every member must report 8.0

mongosh: each replica set member
admin> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )"featureCompatibilityVersion" : { "version" : "8.0" }

Run it per member: getParameter reports the member you are connected to, and the operation is undefined on mongos. The expected line is quoted from the upgrade procedure.

What changes for applications when you move from 8.0 to 9.0?

The 9.0 compatibility changes and the release notes together describe the behavior differences. Most take effect as soon as the 9.0 binary starts, not when FCV is raised, so they reach production during the rolling restart.

MongoDB 8.0 and 9.0 behavior side by side

Switch versions to see what your queries, transactions, and change streams will meet

MongoDB 8.0

AreaMongoDB 8.0
Memory per query operationNo total limit; 100 MB per stage
Open multi-document transactionsNo maxConcurrentMultiDocumentTransactions parameter
$function, $accumulator, $whereDeprecated
Change stream after an electionCursor keeps reading from the same node
BSON validation of incoming dataSet with net.wireObjectCheck
Time series collectionsWritable view over a buckets collection; cannot be renamed
Hedged readsAvailable

MongoDB 9.0

AreaMongoDB 9.0
Memory per query operationDefault limit 1 GB or 20% of server memory, whichever is greater; 100 MB per stage unchanged
Open multi-document transactionsCapped at maxConcurrentMultiDocumentTransactions, default 10000
$function, $accumulator, $whereSupported again on a WASM engine; local Date methods use UTC; unavailable on ppc64le
Change stream after an electiongetMore returns InterruptedDueToReplStateChange (11602); resume from the token
BSON validation of incoming dataAll ingested BSON validated by default; net.wireObjectCheck deprecated
Time series collectionsSingle namespace of compressed buckets; can be renamed
Hedged readsRemoved since 8.1; options ignored with a warning

Binary, not FCV: these rows change when each member restarts on 9.0, so test them on staging before the first production secondary is upgraded.

The per-operation memory limit

In 8.0, a query could use unbounded memory in total as long as each stage stayed under 100 MB. In 9.0, internalQueryMaxMemoryUsageBytesPerOperation caps the whole operation. Operations over the cap fail with ExceededMemoryLimit or QueryExceededMemoryLimitNoDiskUseAllowed. A separate 100 MB default applies to a single expression evaluation.

javascript
// On a 9.0 staging member
db.adminCommand( { getParameter: 1, internalQueryMaxMemoryUsageBytesPerOperation: 1 } )
db.serverStatus().metrics.query.operationsFailedDueToMemoryLimit

Interpretation: the first line shows the effective cap. A rising operationsFailedDueToMemoryLimit counter during a staging replay identifies the reports and large $group or $lookup pipelines that need rewriting or a raised limit.

The transaction cap

The server now rejects new multi-document transactions with TooManyOpenTransactions once 10000 are open. Check your peak on 8.0 before the upgrade.

javascript
// On the 8.0 primary, sampled during peak traffic
db.serverStatus().transactions.currentOpen

Interpretation: if peaks approach the thousands, look for transactions left open by abandoned sessions. Raising the parameter only treats the symptom.

Server-side JavaScript and dates

MongoDB 9.0 removes the 8.0 deprecation of $function, $accumulator, and $where, and runs them on a WebAssembly engine. Local Date operations inside them, including in mapReduce, now evaluate in UTC regardless of the host's TZ. Queries still succeed but return different results. The compatibility page suggests an explicit time zone instead:

javascript
db.events.find( {
   $expr: {
      $lt: [ { $hour: { date: "$occurredAt", timezone: "America/New_York" } }, 9 ]
   }
} )

Interpretation: this form returns the same documents on 8.0 and 9.0, so it is safe to deploy before the upgrade starts.

Check the architecture first

Server-side JavaScript is not available on ppc64le in 9.0, and no setting turns it back on. Rewrite $where, $function, $accumulator, and mapReduce as aggregation stages first.

Smaller changes worth a search

2dsphere key-extraction failures now return codes 510 and 511. A cross-database renameCollection on a replica set locks both collections for the whole operation. The metric metrics.changeStreams.showExpandedEvents is renamed metrics.changeStreams.option.showExpandedEvents.

What did 8.1, 8.2, and 8.3 change that an 8.0 cluster has not seen?

The 9.0 compatibility page describes changes against the release before it. An 8.0 deployment jumps over the 8.1, 8.2, and 8.3 minor releases, so their compatibility notes are also new to you. These are the items from the 8.2 compatibility page (which includes 8.1) and the 8.3 compatibility page that most often matter to operators.

IntroducedChangeWhat to check
8.1Hedged reads removed; readHedgingMode and related parameters have no effectRead preference options and hedgingMetrics dashboards
8.1Applications that run buildInfo before authenticating are incompatibleJVM drivers 3.x and earlier, .NET/C# driver 2.14.1 and earlier
8.1$convert between different binData subtypes returns an errorPipelines that relied on 8.0 returning the original value
8.2orphanCleanupDelaySecs default is 3600 (was 900)Disk headroom after chunk migrations
8.3$facet over 100 MB returns ExceededMemoryLimit instead of code 4031700Error handling that matches the numeric code
8.32dsphereIndexVersion defaults to 4Version 4 indexes must be dropped before FCV goes below 8.3
bash
# Search application code for old error codes and removed options
grep -rnE "4031700|16755|16756|readHedgingMode|maxTimeMSForHedgedReads|hedge" ./src

Interpretation: any hit is code that will behave differently on 9.0. Handlers keyed on old numeric codes stop matching.

Our reading, not MongoDB's checklist

The 9.0 upgrade pages link only to the 9.0 compatibility page. This table is our reading of what 8.0 skips; confirm the rows that matter on staging.

What is new in MongoDB 9.0 that is worth knowing?

From the release notes, these matter most to operators. Some only work after FCV is raised.

  • Per-shape query controls. setQuerySettings accepts maxTimeMS and queryKnobs for one query shape. Both need FCV "9.0". You can also pass a querySettings document on a single command without storing it.
  • The constraint validation level. It applies the validator to every insert and update, blocks bypassing validation, and fails if any existing document violates the rules.
  • Queryable Encryption. Prefix, suffix, and substring queries on encrypted strings are GA. The GA version is incompatible with the 8.2 public preview, and mongocryptd is deprecated in favor of the Automatic Encryption Shared Library.
javascript
// Requires FCV "9.0": cap one regressed query shape at 2 seconds
db.adminCommand( {
   setQuerySettings: { find: "orders", filter: { status: "open" }, $db: "shop" },
   settings: { maxTimeMS: 2000 }
} )

Interpretation: the limit applies to every execution of that shape and takes precedence over a maxTimeMS sent by the client. Setting it to 0 clears it.

Which driver versions are compatible with MongoDB 9.0?

Upgrade drivers before the server. MongoDB's client library compatibility tables mark each driver version as fully or partially compatible with 9.0. First fully compatible versions as of November 2026:

DriverFully compatible with 9.0 from
Node.js7.6
PyMongo4.18
Java (sync and Reactive Streams), Kotlin, Scala5.12
Go2.9
.NET/C#3.10
C / C++2.5 / 4.6
PHP library / Ruby / Rust2.5 / 2.26 / 3.9
bash
# Find the driver versions your services actually ship
npm ls mongodb mongoose
pip show pymongo | grep -i '^version'
go list -m all | grep mongo-driver

Interpretation: compare each result with the table, including batch jobs and CDC connectors.

ODMs need their own check. Known issue SERVER-89953 makes listIndexes report collation: { locale: "simple" } at FCV "9.0". Mongoose reads that as a difference, so syncIndexes() drops and rebuilds unchanged indexes. At startup, that can mean missing indexes and a restart loop. The release notes name Mongoose 9.10.4 and 8.24.5 as fixed. Doctrine ODM and Beanie are also affected, so move index synchronization out of startup and into an explicit deployment step.

How do you run a rolling replica set upgrade from 8.0 to 9.0?

One member at a time, while the others keep serving. The application sees one election, when you step down the primary.

Rolling upgrade: 8.0 replica set to 9.0

Eight steps; step 5 forces an election and step 8 is the point of no easy return

  1. Confirm FCV 8.0 on every member

    Connect to each member directly. Every one must report version 8.0.

    db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
  2. Check member states

    No member may be in ROLLBACK or RECOVERING, and all members must be running.

    rs.status().members.map(m => [m.name, m.stateStr])
  3. Take a backup and test the restore

    This backup is your only fallback if a later downgrade cannot run. Record its time in the change ticket.

  4. Upgrade each secondary, one at a time

    Shut it down, replace the 8.0 binary with 9.0, restart it, and wait for SECONDARY before the next one.

    db.adminCommand( { shutdown: 1 } )
  5. Step down the primary

    Election

    Writes pause until a 9.0 secondary is elected. Drivers with retryable writes retry once.

    rs.stepDown()
  6. Upgrade the former primary

    When rs.status() shows a new PRIMARY, shut down the old one, swap the binary, and restart it.

  7. Burn in at FCV 8.0

    Run production on 9.0 binaries. Going back to 8.0 here is a rolling binary swap to the latest 8.0 patch.

  8. Raise FCV to 9.0

    No easy return

    Run on the primary with no initial sync or index build in progress. The command is idempotent, so a failed run can be retried.

    db.adminCommand( { setFeatureCompatibilityVersion: "9.0", confirm: true } )

Rollback point: until step 8, rolling back means swapping binaries back to the latest 8.0 patch. After step 8, you must remove 9.0-only features and lower FCV before any binary changes, and on Atlas you cannot go back at all without a pinned FCV.

Delayed and hidden members still count: upgrade them as secondaries and include them in the FCV check.

What order do you upgrade a sharded cluster in?

The sharded cluster procedure fixes the order: config servers first, then shards, then every mongos. Each config server replica set and shard follows the replica set pattern above. Back up the config database first.

Sharded cluster upgrade order, 8.0 to 9.0

Follow the numbers; the balancer stays off from step 1 until step 5

Sharded cluster upgrade order from MongoDB 8.0 to 9.0 Step 1: stop the balancer from a mongos. Step 2: upgrade the config server replica set, secondaries first and then the stepped-down primary. Step 3: upgrade the shards one shard at a time, each as a rolling replica set upgrade. Step 4: upgrade every mongos router last. Step 5: start the balancer again. Step 6: after a burn-in period, set the feature compatibility version to 9.0 from a mongos. Stop balancer sh.stopBalancer() Config servers secondaries first Shards one shard at a time mongos every router, last Start balancer sh.startBalancer() FCV 9.0 after burn-in 1 2 3 4 5 6 dashed: wait out the burn-in at FCV 8.0

Step 6 moves metadata: raising FCV to 9.0 migrates sharding metadata from the config servers to the shards, and blocks splits, merges, migrations, and movePrimary until it finishes.

javascript
// From a mongos, before step 2
sh.stopBalancer()
sh.getBalancerState()     // must return false
sh.isBalancerRunning()    // an in-flight migration finishes first

Interpretation: do not restart config servers until getBalancerState() returns false.

Fix the config server connection pool first

Open known issue SERVER-136226 makes every node in a 9.0 sharded cluster open at least ShardingTaskExecutorPoolMinSize connections to each config server. That can exhaust config server connections. If you set that parameter above 1, set ShardingTaskExecutorPoolMinSizeForConfigServers to 1 before you upgrade. With embedded config servers, ask MongoDB Support first.

Two timing traps at step 6

The metadata migration takes longer with many databases, collections, or chunks, and clusters with more than 5,000 time series collections in one database can see write latency spikes. Schedule step 6 in a quiet window, without resharding or movePrimary. An 8.0 mongos cannot connect once FCV is 9.0.

When should you set featureCompatibilityVersion to 9.0?

Only after a burn-in period. The 9.0 upgrade procedure recommends running the new binaries with FCV "8.0" until you are confident a downgrade is unlikely. Nothing is yet persisted in a format 8.0 cannot read. One full business cycle, including month-end jobs, is a sensible floor.

Clear two blockers first. The setFeatureCompatibilityVersion reference says that starting in 9.0, an index build in progress anywhere in the cluster makes the command fail early with BackgroundOperationInProgressForNamespace. An initial sync in progress restarts if FCV changes underneath it.

javascript
// Any index builds still running?
db.adminCommand( {
   currentOp: true,
   $or: [
      { op: "command", "command.createIndexes": { $exists: true } },
      { op: "none", "msg": /^Index Build/ }
   ]
} )

Interpretation: an empty inprog array means no index builds are running. Otherwise, wait or abort them. The command reference also documents a dryRun field, new in 8.3, that simulates the change; try it on staging first.

How far can you roll back from 9.0 to 8.0?

One version: 9.0 can go back to the latest 8.0 patch, but not on to 7.0. How hard it is depends on FCV. The 9.0 to 8.0 downgrade procedures describe both cases.

  • FCV still "8.0". Replace the 9.0 binaries with the latest 8.0 patch, member by member. This is the cheap rollback the burn-in protects.
  • FCV already "9.0". First remove backward-incompatible features. The 9.0 list names views that use $convert to turn an object into binData. Then lower FCV to "8.0", and only then swap binaries.
javascript
// Before lowering FCV: no member may have a newlyAdded flag
use local
db.system.replset.find( { "members.newlyAdded": { $exists: true } } )

// Then, on the primary (or a mongos for a sharded cluster)
db.adminCommand( { setFeatureCompatibilityVersion: "8.0", confirm: true } )

Interpretation: the find must return nothing. If the FCV command fails with CannotDowngrade, 9.0-only data is still present. On a sharded cluster, lowering FCV moves metadata back to the config servers and blocks chunk operations again. Lowering FCV also deletes stored queryKnobs, and raising FCV again does not restore them.

Two sources, two answers

The self-managed downgrade procedures include the FCV-lowering step above. MongoDB's general versions page is stricter and says a downgrade requires that FCV was not raised, or was pinned before the upgrade. Until staging proves the path, treat raising FCV as one-way and keep the step 3 backup.

On MongoDB Atlas

Atlas clusters on auto upgrades have FCV advanced for them. On manual upgrades, the Atlas major version upgrade guide says you cannot downgrade unless you pinned FCV before upgrading. Pinning holds FCV at the previous major version for up to 4 weeks. Atlas recommends testing on a staging cluster restored from a production snapshot first.

Frequently asked questions

Can I upgrade MongoDB from 7.0 directly to 9.0?

No. MongoDB 9.0 accepts upgrades only from an 8.0 or 8.3 release. A 7.0 deployment must first upgrade every member to the latest 8.0 patch and raise featureCompatibilityVersion to 8.0. Only then can it start the 8.0 to 9.0 procedure. Plan two separate maintenance windows.

Which MongoDB 9.0 patch release should I use in production?

Use 9.0.4 or a later patch. MongoDB 9.0.4, released 13 October 2026, fixes five CVEs and SERVER-133518, a shard step-up hang present in 9.0.0 to 9.0.2. The release notes list 9.0.7 as upcoming, so check the known issues table again on the day you upgrade.

Can I downgrade MongoDB 9.0 to 8.0 after setting FCV to 9.0?

On self-managed deployments, the documented procedure allows it with extra work. You remove 9.0-only features, lower featureCompatibilityVersion to 8.0, then replace binaries with the latest 8.0 patch. MongoDB's general versions page is stricter, so test the path on staging first. On Atlas, you cannot downgrade unless FCV was pinned before the upgrade.

Do I need to upgrade my MongoDB driver before upgrading to 9.0?

Yes, check it first. MongoDB's compatibility tables list the first fully compatible versions, such as Node.js driver 7.6, PyMongo 4.18, Java 5.12, Go 2.9, and .NET/C# 3.10. Mongoose users should move to 9.10.4 or 8.24.5.

How long is MongoDB 8.0 supported?

MongoDB's driver compatibility documentation states that MongoDB Server 8.0 reaches end of life in October 2029. MongoDB supports each major version for five years, with optional extended support for Enterprise Advanced customers.

Key takeaways

  • Upgrade from 8.0 at FCV "8.0" to 9.0.4 or later; a 7.0 deployment goes through the latest 8.0 patch first.
  • Test the binary-level changes on staging: the memory limit, the transaction cap, UTC dates in server-side JavaScript, and change stream resumes.
  • Read the 8.1, 8.2, and 8.3 compatibility notes too, and move every driver and ODM to a fully compatible version before the server.
  • Sharded clusters: balancer off, config servers, shards, mongos, balancer on; fix ShardingTaskExecutorPoolMinSize first.
  • Raise FCV to "9.0" only after a burn-in period, with no index builds running, and treat it as one-way until a staging downgrade proves otherwise.

Plan your MongoDB 9.0 upgrade with JusDB

JusDB's MongoDB migration and upgrade team can review your 8.0 deployment against the 9.0 compatibility changes, check drivers and ODMs across your services, and write a rolling upgrade runbook with a rehearsed rollback path for your replica sets or sharded clusters.

Bring your topology, versions and FCV, driver inventory, and available maintenance windows. Your team approves every production change.

Share this article

Database engineering notes

Articles like this one, in your inbox. No spam, unsubscribe anytime.

JusDB Team

Official JusDB content team

Keep reading

Moving a Multi-Database Valkey Instance into a 9.x Cluster

Move a Valkey instance that uses SELECT 1 to 15 into a 9.x cluster: keep or remap databases, copy each one, verify counts per database, and keep a way back.

Redis18 minNov 10, 2026
Read

Valkey Keyspace Notifications in Production: Expired Events, hexpired and Cluster Mode

Run Valkey keyspace notifications in production: why expired and hexpired events lag the TTL, how to subscribe on every cluster node, and when a stream is safer.

Redis20 minNov 10, 2026
Read

Valkey GLIDE in Production: AZ-Affinity Reads and Migrating from Legacy Clients

Configure Valkey GLIDE AZ-affinity reads on servers and clients, learn what GLIDE 2.5.3 does not support, and migrate from redis-py, Jedis, ioredis, or go-redis one service at a time.

Redis20 minNov 10, 2026
Read