NoSQL Databases

MongoDB 8.0 Replication: New Features, Improvements, and What Changed

MongoDB 8.0 brings significant replication improvements including faster elections, durable oplog writes, and changes to write concern behavior. Here's what changed and how to take advantage of it.

JusDB Team
March 11, 2025
Updated May 16, 2026
8 min read
170 views

Your e-commerce platform is mid-peak when the primary goes down. The replica set needs to elect a new primary — and for the next 12 seconds, every write attempt returns NotWritablePrimary while the election resolves. Twelve seconds of write unavailability during a checkout flow translates directly into abandoned carts and lost revenue. If you have been tolerating that kind of failover window as a cost of doing business with MongoDB, version 8.0 changes the calculus. MongoDB 8.0 ships a fundamentally revised election protocol, durable oplog write behavior, and tightened write concern semantics — all of which reduce the blast radius of a primary failure and make replica set operations more predictable. This post walks through what changed, what to watch for, and how to configure your replica sets to take full advantage.

TL;DR
  • MongoDB 8.0 reduces election time through a new pre-vote mechanism and improved heartbeat handling — typical failovers complete in under 5 seconds on well-configured replica sets.
  • Oplog writes are now durable by default on the primary — journalCommitInterval behavior changed, which affects write latency and durability guarantees.
  • The default write concern changed from w: 1 to w: "majority" for replica sets — existing applications that relied on implicit w: 1 behavior need review.
  • New rs.status() fields expose election metrics and replication lag at higher resolution, improving observability.
  • Rolling upgrades from MongoDB 7.0 to 8.0 follow the standard procedure but require FCV advancement to unlock new replication features.

MongoDB 8.0 Replication Overview

MongoDB 8.0, released in mid-2024, is the latest long-term support (LTS) release and the successor to MongoDB 7.0. On the replication front, the engineering team focused on three areas: election speed, oplog durability, and write concern defaults. These are not incremental tweaks — they represent the most significant changes to replica set behavior since the introduction of the Raft-inspired election protocol in MongoDB 3.2.

What Stayed the Same

The core replication architecture is unchanged. Each replica set still consists of a primary and up to 49 data-bearing members (practical limit remains one primary and up to 6 secondaries in most production deployments). Secondaries still apply oplog entries in document-level order using multiple threads via the parallel apply pipeline. Arbiter members still exist, though they remain inadvisable for new deployments. The rs.initiate(), rs.add(), and rs.remove() management commands behave identically.

What Changed

The changes that matter operationally are: a new pre-vote phase in elections that prevents split-brain scenarios more reliably, changes to how oplog writes are committed to the journal, a new default write concern for replica set members, and additional diagnostic output in rs.status() and db.adminCommand({ replSetGetStatus: 1 }). Each of these is covered in detail in the sections below.


Faster Elections — How MongoDB 8.0 Reduces Failover Time

Election time is the single most important availability metric for a replica set. Every second spent electing a new primary is a second of write unavailability. MongoDB 8.0 reduces typical election duration from the 10–15 second range in 7.0 to under 5 seconds on well-configured sets — and in some topologies, under 2 seconds.

The Pre-Vote Phase

Prior to 8.0, when a secondary detected it had not received a heartbeat from the primary for longer than electionTimeoutMillis (default: 10 seconds), it immediately called an election. This meant a secondary that was isolated from the primary but could still reach other secondaries could trigger an unnecessary election — disrupting the set even when the primary was still healthy and reachable by the majority.

MongoDB 8.0 introduces a pre-vote round before any formal election begins. When a secondary's heartbeat timeout fires, it first sends a replSetRequestVotes dry run to all other set members with a dryRun: true flag. Members respond with whether they would grant the vote in a real election — based on oplog position, not leadership intent. Only if the pre-vote succeeds (i.e., the candidate would win) does it escalate to a formal election. This eliminates elections triggered by network partitions that the candidate could not actually win, reducing spurious failovers by a meaningful margin in high-latency multi-region deployments.

Tuning electionTimeoutMillis for Your Topology

The pre-vote phase means you can safely reduce electionTimeoutMillis without the risk of triggering constant false elections that plagued earlier versions. For single-region deployments with low inter-node latency, 5000ms is a reasonable target. For multi-region sets, keep it at 10000ms or above to account for cross-region heartbeat round-trip times.

javascript
// Check current election timeout on a running replica set
rs.conf().settings.electionTimeoutMillis

// Reconfigure electionTimeoutMillis — applies to the running set immediately
var cfg = rs.conf();
cfg.settings.electionTimeoutMillis = 5000; // 5 seconds for single-region
rs.reconfig(cfg);

// Verify the change applied
rs.conf().settings.electionTimeoutMillis
Warning

Reducing electionTimeoutMillis below 5000ms in multi-region deployments or environments with network instability will cause false primaries to step down and trigger unnecessary elections under transient packet loss. Always validate the change against your p99 heartbeat round-trip latency before applying it to production. Use rs.status().members[].pingMs as a baseline.

Measuring Your Election Performance

MongoDB 8.0 adds new fields to rs.status() that surface election timing data. Use these to verify your post-upgrade election performance before and after tuning:

javascript
// Full replica set status with election timing
var status = rs.status();

// Check each member's election-related metrics
status.members.forEach(function(m) {
  printjson({
    name: m.name,
    state: m.stateStr,
    pingMs: m.pingMs,
    lastHeartbeatMessage: m.lastHeartbeatMessage,
    electionDate: m.electionDate,
    configVersion: m.configVersion
  });
});

// Check election history from the primary
db.adminCommand({ replSetGetStatus: 1 }).electionCandidateMetrics

Oplog Improvements — Durable Writes and Compression

The operations log (oplog) is the backbone of MongoDB replication. Every write on the primary is recorded to the oplog as a BSON document, and secondaries tail the oplog to apply changes in order. MongoDB 8.0 changes both how oplog entries are persisted on the primary and how the oplog is stored on disk.

Durable Oplog Writes by Default

In MongoDB 7.0 and earlier, oplog entries were written to the WiredTiger storage engine's in-memory cache and committed to the journal on a configurable interval (journalCommitInterval, default 100ms). This meant that in the window between a write being acknowledged (with w: 1) and the next journal commit, the write existed only in memory. A power failure or hard crash in that window could result in the write being lost from the oplog — and therefore not replicated.

MongoDB 8.0 changes this: oplog writes on the primary are now committed to the journal synchronously before the write is acknowledged at any write concern level. The oplog is treated as a durable write path regardless of journalCommitInterval. This closes a theoretical durability gap and makes the oplog consistent with the WAL semantics most DBAs expect from a transaction log.

Tip

If you previously ran with j: false in your write concern to avoid the journal commit overhead, that optimization no longer applies to oplog writes in 8.0. The journal commit now happens on the oplog write path regardless. You may see a slight increase in p99 write latency after upgrading — this is expected and represents genuine durability improvement, not a regression.

Oplog Compression

MongoDB 8.0 introduces Zstandard (zstd) compression for the oplog collection by default on new replica sets initialized at FCV 8.0. Zstd offers significantly better compression ratios than the Snappy default used for regular collections, and it operates at competitive decompression speeds. On write-heavy workloads, oplog compression reduces the oplog disk footprint by 40–60% compared to uncompressed storage — this translates directly to longer oplog retention windows for the same disk allocation.

javascript
// Check current oplog size and retention window on the primary
db.adminCommand({ replSetGetStatus: 1 }).oplogSizeMB

// Inspect oplog stats including compression ratio (requires FCV 8.0)
use local;
db.oplog.rs.stats({ scale: 1048576 });
// Look at: size (MB), storageSize (MB), compression ratio = size / storageSize

// Check oplog retention window in hours
var oplogStats = rs.printReplicationInfo();
// Output includes "log length start to end" and "oplog first event time"

// Set a minimum oplog retention window (independent of oplog size limit)
// New in MongoDB 5.0+, works in 8.0 with improved compression:
db.adminCommand({
  replSetResizeOplog: 1,
  minRetentionHours: 24   // Guarantee 24 hours of oplog regardless of size
});
Warning

Oplog compression with zstd only applies to replica sets initialized at FCV 8.0 or higher. Replica sets upgraded from 7.0 that advance to FCV 8.0 will not retroactively compress the existing oplog — new oplog entries after the FCV advancement will use zstd, but existing entries remain in their original format. Plan for a gradual transition period of 1–2x your oplog retention window before achieving the full storage savings.


Write Concern Changes in MongoDB 8.0

This is the change most likely to affect existing applications without a code change. MongoDB 8.0 changes the default write concern for replica set connections from w: 1 (acknowledged by the primary only) to w: "majority" (acknowledged by a majority of voting members). This is a breaking change for applications that relied on the implicit w: 1 default for performance and did not explicitly specify a write concern.

What the Change Means

With w: "majority", a write is not acknowledged to the application until it has been committed to the oplog on a majority of voting replica set members and durably committed to their journals. For a three-member replica set, this means the primary plus one secondary must confirm the write before the driver returns success. The practical effect is that w: "majority" writes have higher latency than w: 1 writes — the latency floor is bounded by the replication lag to the second-fastest secondary plus the network round-trip to that member.

javascript
// Check the current default write concern on a replica set
db.adminCommand({ getDefaultRWConcern: 1 });

// Example output in MongoDB 8.0 on a replica set:
// {
//   "defaultWriteConcern" : { "w" : "majority", "wtimeout" : 0 },
//   "defaultReadConcern" : { "level" : "local" },
//   "defaultWriteConcernSource" : "implicit",
//   ...
// }

// If your application needs w: 1 behavior explicitly, set it at the collection level:
db.orders.insertOne(
  { item: "widget", qty: 100 },
  { writeConcern: { w: 1 } }  // Explicit override — primary ack only
);

// Or set a custom default write concern at the replica set level:
db.adminCommand({
  setDefaultRWConcern: 1,
  defaultWriteConcern: { w: 1, wtimeout: 5000 }
});

Impact on Write Latency

On a single-region replica set with intra-datacenter replication (sub-millisecond network latency between members), the switch from w: 1 to w: "majority" typically adds 1–3ms to write operations. On a multi-region set where the nearest secondary is 50ms away, that becomes 50–100ms of additional write latency. Run a write latency benchmark against your specific topology before and after upgrading to quantify the impact.

javascript
// Benchmark write latency at different write concerns before upgrading
// Run from mongosh on your production replica set during a low-traffic window

function benchmarkWriteConcern(wc, iterations) {
  var times = [];
  for (var i = 0; i < iterations; i++) {
    var start = Date.now();
    db.bench_wc.insertOne(
      { _id: new ObjectId(), ts: new Date(), val: Math.random() },
      { writeConcern: wc }
    );
    times.push(Date.now() - start);
  }
  db.bench_wc.drop();
  times.sort(function(a,b){return a-b;});
  return {
    writeConcern: JSON.stringify(wc),
    avg: (times.reduce(function(a,b){return a+b;},0) / times.length).toFixed(2) + "ms",
    p50: times[Math.floor(times.length * 0.50)] + "ms",
    p99: times[Math.floor(times.length * 0.99)] + "ms"
  };
}

printjson(benchmarkWriteConcern({ w: 1 }, 500));
printjson(benchmarkWriteConcern({ w: "majority" }, 500));
Warning

Applications that issue bulk write operations with implicit write concern and expect low-latency acknowledgment will see a material latency increase after upgrading to 8.0 without explicit write concern configuration. Audit your application driver configuration and explicitly set w: 1 where write latency is more important than durability guarantees — but understand the tradeoff: a primary crash before the write reaches a secondary means data loss with w: 1.


Replica Set Configuration Best Practices for 8.0

With the changes in 8.0, several configuration practices that were optional before become important to review before and after upgrading.

Set explicit writeConcernMajorityJournalDefault

In MongoDB 8.0, the writeConcernMajorityJournalDefault replica set configuration option now defaults to true even on deployments without journaling explicitly configured. Verify this is set correctly for your durability requirements:

javascript
// Inspect your replica set configuration
var cfg = rs.conf();
printjson({
  writeConcernMajorityJournalDefault: cfg.writeConcernMajorityJournalDefault,
  members: cfg.members.map(function(m) {
    return {
      host: m.host,
      priority: m.priority,
      votes: m.votes,
      hidden: m.hidden,
      tags: m.tags
    };
  }),
  settings: cfg.settings
});

// If writeConcernMajorityJournalDefault is missing or false, set it explicitly:
cfg.writeConcernMajorityJournalDefault = true;
rs.reconfig(cfg);

Configure chainingAllowed for Predictable Replication Paths

Secondary chaining — where one secondary replicates from another secondary rather than directly from the primary — is enabled by default in all MongoDB versions. In 8.0, with the faster election protocol, chained replication can cause secondaries to miss writes during election windows if the chain source steps down. For topologies where replication lag predictability matters, disable chaining:

javascript
// Disable chaining — all secondaries replicate directly from the primary
var cfg = rs.conf();
cfg.settings.chainingAllowed = false;
rs.reconfig(cfg);

// Verify all members are replicating from the primary
rs.status().members.forEach(function(m) {
  if (m.stateStr === "SECONDARY") {
    print(m.name + " syncing from: " + m.syncSourceHost);
  }
});

Use Tag Sets for Targeted Write Concern in Multi-Region Setups

If you run a multi-region replica set and need writes acknowledged by members in a specific region (e.g., your primary region), use replica set tags combined with a custom write concern to avoid incurring cross-region write latency on every operation:

javascript
// Add datacenter tags to replica set members
var cfg = rs.conf();
cfg.members[0].tags = { dc: "us-east-1", role: "primary" };
cfg.members[1].tags = { dc: "us-east-1", role: "secondary" };
cfg.members[2].tags = { dc: "eu-west-1", role: "secondary" };

// Define a custom write concern using the tag
cfg.settings.getLastErrorModes = {
  primaryDC: { "dc": 1 }  // At least one member with dc tag must ack
};
rs.reconfig(cfg);

// Use the custom write concern in your application
db.orders.insertOne(
  { item: "widget" },
  { writeConcern: { w: "primaryDC", wtimeout: 5000 } }
);

Monitoring Replication Health in MongoDB 8.0

MongoDB 8.0 adds diagnostic output that makes it easier to detect replication lag, election anomalies, and oplog pressure before they cause application impact.

Key rs.status() Fields in 8.0

javascript
// Comprehensive replication health check — run on the primary
var status = rs.status();

// Check replication lag per secondary
status.members.filter(function(m) {
  return m.stateStr === "SECONDARY";
}).forEach(function(m) {
  var lagSecs = (status.members.find(function(p) {
    return p.stateStr === "PRIMARY";
  }).optime.ts.getHighBits() - m.optime.ts.getHighBits());

  print(m.name + " replication lag: " + lagSecs + "s | ping: " + m.pingMs + "ms");
});

// Check optime of primary vs. each secondary
var primary = status.members.find(function(m) { return m.stateStr === "PRIMARY"; });
print("Primary optime: " + primary.optime.ts);
print("Primary optimeDate: " + primary.optimeDate);

// Election candidate metrics (new in 8.0)
var replStatus = db.adminCommand({ replSetGetStatus: 1 });
if (replStatus.electionCandidateMetrics) {
  printjson(replStatus.electionCandidateMetrics);
}
if (replStatus.electionParticipantMetrics) {
  printjson(replStatus.electionParticipantMetrics);
}

Setting Up Replication Lag Alerting

The MongoDB Prometheus exporter exposes replication lag as mongodb_replset_member_replication_lag per member. For self-managed deployments without Prometheus, use a periodic mongosh script run via cron or a monitoring agent:

javascript
// Replication health check script — save as /opt/mongodb/check-repl-lag.js
// Run with: mongosh --quiet --file /opt/mongodb/check-repl-lag.js

var status = rs.status();
var primary = status.members.find(function(m) { return m.stateStr === "PRIMARY"; });

if (!primary) {
  print("CRITICAL: No primary found in replica set");
  quit(2);
}

var maxLag = 0;
var laggingMembers = [];

status.members.filter(function(m) {
  return m.stateStr === "SECONDARY";
}).forEach(function(m) {
  var lagSecs = primary.optime.ts.getHighBits() - m.optime.ts.getHighBits();
  if (lagSecs > maxLag) maxLag = lagSecs;
  if (lagSecs > 30) {  // Alert threshold: 30 seconds
    laggingMembers.push(m.name + " (" + lagSecs + "s lag)");
  }
});

if (laggingMembers.length > 0) {
  print("WARNING: Secondaries exceeding lag threshold: " + laggingMembers.join(", "));
  quit(1);
} else {
  print("OK: Max replication lag " + maxLag + "s across " +
        (status.members.length - 1) + " secondaries");
  quit(0);
}

Upgrading Your Replica Set to MongoDB 8.0

The upgrade from MongoDB 7.0 to 8.0 follows MongoDB's standard rolling upgrade procedure. You must upgrade through each major version sequentially — if you are running 6.0, you must upgrade to 7.0 first, then 8.0. Skipping major versions is not supported.

Step 1: Verify Current FCV and Version

javascript
// Check current MongoDB version and Feature Compatibility Version
db.version();
// Expected: "7.0.x" before upgrading

db.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 });
// Expected: { featureCompatibilityVersion: { version: "7.0" }, ok: 1 }

// Check replica set status — all members should be HEALTHY before upgrading
rs.status().members.forEach(function(m) {
  print(m.name + ": " + m.stateStr + " | health: " + m.health);
});

Step 2: Rolling Upgrade — Secondaries First

bash
# On each secondary node (one at a time):
# 1. Stop the mongod process
sudo systemctl stop mongod

# 2. Replace the binary with MongoDB 8.0
# (method varies by OS/package manager — using apt as example)
sudo apt-get install -y mongodb-org=8.0.x mongodb-org-server=8.0.x \
  mongodb-org-mongos=8.0.x mongodb-org-tools=8.0.x

# 3. Start mongod with the new binary
sudo systemctl start mongod

# 4. Verify the secondary rejoined the set before proceeding to the next member
mongosh --eval "rs.status().members.filter(m => m.stateStr === 'SECONDARY').map(m => m.name)"
javascript
// After upgrading each secondary, verify it is caught up
// before upgrading the next member
rs.printSecondaryReplicationInfo();
// Wait until replication lag is < 5 seconds before continuing

Step 3: Step Down and Upgrade the Primary

javascript
// Step down the primary — triggers an election on the upgraded secondaries
rs.stepDown(60);  // 60 second freeze period prevents old primary from re-electing
// Wait for a secondary to become primary, then upgrade the former primary
bash
# On the former primary (now a secondary):
sudo systemctl stop mongod
sudo apt-get install -y mongodb-org=8.0.x
sudo systemctl start mongod

Step 4: Advance the Feature Compatibility Version

Warning

Advancing the FCV is a one-way operation — you cannot downgrade the FCV below the current version without fully downgrading all replica set members first. Do not advance the FCV until all members of the set are running MongoDB 8.0 binaries and you are confident in the upgrade. The new replication features (zstd oplog compression, pre-vote elections, new default write concern) only activate after FCV 8.0 is set.

javascript
// Advance FCV only after all members are on MongoDB 8.0 binaries
// Run on the primary
db.adminCommand({ setFeatureCompatibilityVersion: "8.0", confirm: true });

// Verify FCV advanced successfully
db.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 });
// Expected: { featureCompatibilityVersion: { version: "8.0" }, ok: 1 }

// Confirm new default write concern is active
db.adminCommand({ getDefaultRWConcern: 1 });
// defaultWriteConcern should now show w: "majority"
Key Takeaways
  • MongoDB 8.0's pre-vote election protocol eliminates a significant class of spurious elections in partitioned topologies — set electionTimeoutMillis to 5000ms on single-region deployments to realize the full failover speed improvement.
  • Oplog writes are now durably committed to the journal before acknowledgment — expect a slight increase in write p99 latency after upgrading, which reflects genuine durability improvement rather than regression.
  • The default write concern changed to w: "majority" — audit your application driver configuration before upgrading and explicitly set write concerns where latency versus durability tradeoffs are intentional.
  • Oplog zstd compression (after FCV 8.0 advancement) reduces oplog disk footprint by 40–60%, enabling longer retention windows without increasing disk allocation.
  • Disable secondary chaining (chainingAllowed: false) in latency-sensitive topologies to prevent replication chain disruption during elections.
  • Advance the FCV only after all replica set members are running 8.0 binaries — FCV advancement is irreversible without a full binary downgrade.
  • Use rs.status() election candidate and participant metrics added in 8.0 to baseline your post-upgrade election performance and validate tuning changes.

Working with JusDB on MongoDB Replica Sets

JusDB manages MongoDB replica sets for engineering teams — version upgrades, election tuning, write concern configuration, and 24/7 replication monitoring. Our DBAs ensure your replica sets handle failovers transparently with minimal application impact.

Explore JusDB MongoDB Management →  |  Talk to a DBA

Related reading:

Share this article