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.
- 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).
// 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.
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.
// 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
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
| Area | MongoDB 8.0 |
|---|---|
| Memory per query operation | No total limit; 100 MB per stage |
| Open multi-document transactions | No maxConcurrentMultiDocumentTransactions parameter |
$function, $accumulator, $where | Deprecated |
| Change stream after an election | Cursor keeps reading from the same node |
| BSON validation of incoming data | Set with net.wireObjectCheck |
| Time series collections | Writable view over a buckets collection; cannot be renamed |
| Hedged reads | Available |
MongoDB 9.0
| Area | MongoDB 9.0 |
|---|---|
| Memory per query operation | Default limit 1 GB or 20% of server memory, whichever is greater; 100 MB per stage unchanged |
| Open multi-document transactions | Capped at maxConcurrentMultiDocumentTransactions, default 10000 |
$function, $accumulator, $where | Supported again on a WASM engine; local Date methods use UTC; unavailable on ppc64le |
| Change stream after an election | getMore returns InterruptedDueToReplStateChange (11602); resume from the token |
| BSON validation of incoming data | All ingested BSON validated by default; net.wireObjectCheck deprecated |
| Time series collections | Single namespace of compressed buckets; can be renamed |
| Hedged reads | Removed 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.
// On a 9.0 staging member
db.adminCommand( { getParameter: 1, internalQueryMaxMemoryUsageBytesPerOperation: 1 } )
db.serverStatus().metrics.query.operationsFailedDueToMemoryLimitInterpretation: 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.
// On the 8.0 primary, sampled during peak traffic
db.serverStatus().transactions.currentOpenInterpretation: 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:
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.
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.
| Introduced | Change | What to check |
|---|---|---|
| 8.1 | Hedged reads removed; readHedgingMode and related parameters have no effect | Read preference options and hedgingMetrics dashboards |
| 8.1 | Applications that run buildInfo before authenticating are incompatible | JVM drivers 3.x and earlier, .NET/C# driver 2.14.1 and earlier |
| 8.1 | $convert between different binData subtypes returns an error | Pipelines that relied on 8.0 returning the original value |
| 8.2 | orphanCleanupDelaySecs default is 3600 (was 900) | Disk headroom after chunk migrations |
| 8.3 | $facet over 100 MB returns ExceededMemoryLimit instead of code 4031700 | Error handling that matches the numeric code |
| 8.3 | 2dsphereIndexVersion defaults to 4 | Version 4 indexes must be dropped before FCV goes below 8.3 |
# Search application code for old error codes and removed options
grep -rnE "4031700|16755|16756|readHedgingMode|maxTimeMSForHedgedReads|hedge" ./srcInterpretation: any hit is code that will behave differently on 9.0. Handlers keyed on old numeric codes stop matching.
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.
setQuerySettingsacceptsmaxTimeMSandqueryKnobsfor one query shape. Both need FCV"9.0". You can also pass aquerySettingsdocument on a single command without storing it. - The
constraintvalidation 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
mongocryptdis deprecated in favor of the Automatic Encryption Shared Library.
// 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:
| Driver | Fully compatible with 9.0 from |
|---|---|
| Node.js | 7.6 |
| PyMongo | 4.18 |
| Java (sync and Reactive Streams), Kotlin, Scala | 5.12 |
| Go | 2.9 |
| .NET/C# | 3.10 |
| C / C++ | 2.5 / 4.6 |
| PHP library / Ruby / Rust | 2.5 / 2.26 / 3.9 |
# Find the driver versions your services actually ship
npm ls mongodb mongoose
pip show pymongo | grep -i '^version'
go list -m all | grep mongo-driverInterpretation: 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
-
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 } ) -
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]) -
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.
-
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 } ) -
Step down the primary
ElectionWrites pause until a 9.0 secondary is elected. Drivers with retryable writes retry once.
rs.stepDown() -
Upgrade the former primary
When rs.status() shows a new PRIMARY, shut down the old one, swap the binary, and restart it.
-
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.
-
Raise FCV to 9.0
No easy returnRun 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
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.
// From a mongos, before step 2
sh.stopBalancer()
sh.getBalancerState() // must return false
sh.isBalancerRunning() // an in-flight migration finishes firstInterpretation: 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.
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.
// 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
$convertto turn an object into binData. Then lower FCV to"8.0", and only then swap binaries.
// 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.
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
ShardingTaskExecutorPoolMinSizefirst. - 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.