MongoDB Replica Set Configuration
Table of Contents
1. What We Are Building
| Hostname | IP | Starting role |
|---|---|---|
mongo01 | 192.168.2.101 | Primary |
mongo02 | 192.168.2.102 | Secondary 1 |
mongo03 | 192.168.3.103 | Secondary 2 |
Replica set name: rs0. Port: 27017. MongoDB 7.0.43 Enterprise on all three servers. OS user: mongop, group: mongogrp.
Application
|
| writes (and reads)
v
+-------------+
| mongo01 | PRIMARY only node that accepts writes
| (oplog) |
+-------------+
^ ^
pull oplog | | pull oplog secondaries copy the oplog and
| | apply it themselves
+-----------+ +-----------+
| mongo02 | | mongo03 | SECONDARY
| (oplog) | | (oplog) |
+-----------+ +-----------+
Every node sends a heartbeat to every other node every 2 seconds.
Why three nodes? A new primary is elected only by a majority of voting members. With 3 nodes the majority is 2, so the set survives the loss of any one node. With 2 nodes the majority is also 2, so losing one node leaves no primary. This is why the minimum useful set is 3 members.
The primary is only a role. After a failover, mongo02 can become primary. It is like primary and standby swapping roles in Data Guard.
2. Prerequisites
This guide covers only the replica set steps. The installation is documented separately:
📘 Installation guide: MongoDB 7.0 Enterprise Installation on Linux using Tarball Method. Complete it on all three servers before you continue.
Before you start, every server must match this state:
| Item | Expected state |
|---|---|
Binaries and mongosh | In /app/mongodb/7.0.43/bin |
| Config file | /app/mongodb/config/mongod.conf, with bindIp set to that server’s own IP |
| OS tuning | THP disabled, ulimits set (installation guide, sections 9 and 10) |
| SELinux | SELinux is disabled because this is a lab setup. |
| Service | mongod.service enabled, managed with systemctl only |
Check the service and SELinux label on each server:
[root@mongo02 ~]# systemctl is-enabled mongod
[root@mongo02 ~]# getenforce
Permissive
[root@mongo02 ~]# ls -Z /app/mongodb/7.0.43/bin/mongod
system_u:object_r:mongod_exec_t:s0 /app/mongodb/7.0.43/bin/mongod
[root@mongo02 ~]#
⚠️ Note: mongo03 is on a different subnet (192.168.3.x). Make sure routing and firewalls allow port 27017 in both directions between all three servers.
3. Prepare mongo02 and mongo03
If you followed the installation guide to the end on mongo02 and mongo03, each one is a standalone server with its own data and its own admin user. A secondary must start empty, because initial sync erases everything on it and copies the data from the primary. Start with a clean data directory on both:
[root@mongo02 ~]# systemctl stop mongod
[root@mongo02 ~]# pgrep -a mongod
[root@mongo02 ~]# rm -rf /data/mongodb/*
[root@mongo02 ~]# ls -la /data/mongodb
total 0
[root@mongo02 ~]#
Repeat on mongo03. Leave mongo01 running with its data and admin user.
⚠️ Note: After initial sync, mongo02 and mongo03 have the same users as mongo01. Log in with the admin password that you created on mongo01. Any user created earlier on a secondary is lost.
4. Network: Hosts File and Firewall
Step 1 – Hostnames. Every server must resolve every hostname. Use DNS, or add this to /etc/hosts on all three servers:
[root@mongo01 ~]# cat >> /etc/hosts << 'EOF'
192.168.2.101 mongo01
192.168.2.102 mongo02
192.168.3.103 mongo03
EOF
[root@mongo01 ~]# getent hosts mongo01 mongo02 mongo03
Step 2 – Firewall. The installation guide opens port 27017 to every source. For a replica set, replace that with rules that allow only the three servers (add your application servers later). Run on all three:
[root@mongo01 ~]# firewall-cmd --permanent --remove-port=27017/tcp
success
[root@mongo01 ~]#
[root@mongo01 ~]# for ip in 192.168.2.101 192.168.2.102 192.168.3.103; do
firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=${ip} port port=27017 protocol=tcp accept"
done
success
success
success
[root@mongo01 ~]# firewall-cmd --reload
success
[root@mongo01 ~]# firewall-cmd --list-rich-rules
rule family="ipv4" source address="192.168.2.101" port port="27017" protocol="tcp" accept
rule family="ipv4" source address="192.168.2.102" port port="27017" protocol="tcp" accept
rule family="ipv4" source address="192.168.3.103" port port="27017" protocol="tcp" accept
[root@mongo01 ~]#
| MongoDB | Oracle (Data Guard) |
|---|---|
| Open port 27017 between servers | Listener and tnsnames entries between servers, port 1521 |
| Shared keyfile | Shared password file (orapw) |
5. Copy the Keyfile to All Nodes
Replica set members authenticate to each other with a shared keyfile, similar in purpose to the password file used between Data Guard databases. All three must hold the same file. Use the one created on mongo01 (installation guide, section 14) and overwrite any keyfile that exists on the other two.
# On mongo01
[root@mongo01 ~]# scp -p /app/mongodb/keyfile/mongodb-keyfile root@mongo02:/app/mongodb/keyfile/
[root@mongo01 ~]# scp -p /app/mongodb/keyfile/mongodb-keyfile root@mongo03:/app/mongodb/keyfile/
# On mongo02
[root@mongo02 ~]# chown mongop:mongogrp /app/mongodb/keyfile/mongodb-keyfile
[root@mongo02 ~]# chmod 400 /app/mongodb/keyfile/mongodb-keyfile
[root@mongo02 ~]# ls -l /app/mongodb/keyfile/mongodb-keyfile
-r--------. 1 mongop mongogrp 1024 Nov 6 08:41 /app/mongodb/keyfile/mongodb-keyfile
[root@mongo02 ~]#
# On mongo03
[root@mongo03 ~]# chown mongop:mongogrp /app/mongodb/keyfile/mongodb-keyfile
[root@mongo03 ~]# chmod 400 /app/mongodb/keyfile/mongodb-keyfile
[root@mongo03 ~]# ls -l /app/mongodb/keyfile/mongodb-keyfile
-r--------. 1 mongop mongogrp 1024 Nov 6 08:41 /app/mongodb/keyfile/mongodb-keyfile
[root@mongo03 ~]#
# On all three: the checksum must be identical
[root@mongo01 ~]# md5sum /app/mongodb/keyfile/mongodb-keyfile
afa3e0d477c8938597441cb310ef43b3 /app/mongodb/keyfile/mongodb-keyfile
[root@mongo01 ~]#
[root@mongo02 ~]# md5sum /app/mongodb/keyfile/mongodb-keyfile
afa3e0d477c8938597441cb310ef43b3 /app/mongodb/keyfile/mongodb-keyfile
[root@mongo02 ~]#
[root@mongo03 ~]# md5sum /app/mongodb/keyfile/mongodb-keyfile
afa3e0d477c8938597441cb310ef43b3 /app/mongodb/keyfile/mongodb-keyfile
[root@mongo03 ~]#
6. Enable Replication in mongod.conf
The installation guide leaves the replication section commented out. Uncomment it on all three servers, as mongop. The security section (authorization and keyFile) is already enabled from the installation guide, so do not change it.
[mongop@mongo01 ~]$ cp -p /app/mongodb/config/mongod.conf /app/mongodb/config/mongod.conf.bak
Before:
# --- Replication (uncomment for replica set) ---
#replication:
# replSetName: rs0
# oplogSizeMB: 10240
[mongop@mongo01 ~]$
[mongop@mongo01 ~]$ sed -i \
-e 's/^#replication:/replication:/' \
-e 's/^# *replSetName: rs0/ replSetName: rs0/' \
-e 's/^# *oplogSizeMB: 10240/ oplogSizeMB: 10240/' \
/app/mongodb/config/mongod.conf
[mongop@mongo01 ~]$ egrep -i -A2 'replication|bindIp|^security' /app/mongodb/config/mongod.conf
bindIp: 127.0.0.1,192.168.2.101
maxIncomingConnections: 51200
--
security:
authorization: enabled
keyFile: /app/mongodb/keyfile/mongodb-keyfile
--
replication:
replSetName: rs0
oplogSizeMB: 10240
[mongop@mongo02 ~]$ cp -p /app/mongodb/config/mongod.conf /app/mongodb/config/mongod.conf.bak
[mongop@mongo02 ~]$ sed -i \
-e 's/^#replication:/replication:/' \
-e 's/^# *replSetName: rs0/ replSetName: rs0/' \
-e 's/^# *oplogSizeMB: 10240/ oplogSizeMB: 10240/' \
/app/mongodb/config/mongod.conf
[mongop@mongo02 ~]$ egrep -i -A2 'replication|bindIp|^security' /app/mongodb/config/mongod.conf
bindIp: 127.0.0.1,192.168.2.102 # change per node
maxIncomingConnections: 51200
--
security:
authorization: enabled
keyFile: /app/mongodb/keyfile/mongodb-keyfile
--
# --- Replication (uncomment for replica set) ---
replication:
replSetName: rs0
oplogSizeMB: 10240
[mongop@mongo02 ~]$
[mongop@mongo03 ~]$ cp -p /app/mongodb/config/mongod.conf /app/mongodb/config/mongod.conf.bak
[mongop@mongo03 ~]$ sed -i \
-e 's/^#replication:/replication:/' \
-e 's/^# *replSetName: rs0/ replSetName: rs0/' \
-e 's/^# *oplogSizeMB: 10240/ oplogSizeMB: 10240/' \
/app/mongodb/config/mongod.conf
[mongop@mongo03 ~]$ egrep -i -A2 'replication|bindIp|^security' /app/mongodb/config/mongod.conf
bindIp: 127.0.0.1,192.168.3.103 # change per node
maxIncomingConnections: 51200
--
security:
authorization: enabled
keyFile: /app/mongodb/keyfile/mongodb-keyfile
--
# --- Replication (uncomment for replica set) ---
replication:
replSetName: rs0
oplogSizeMB: 10240
[mongop@mongo03 ~]$Check that bindIp on each server has its own IP:
| Server | bindIp |
|---|---|
mongo01 | 127.0.0.1,192.168.2.101 |
mongo02 | 127.0.0.1,192.168.2.102 |
mongo03 | 127.0.0.1,192.168.3.103 |
Restart (or start) mongod on all three with systemctl:
[root@mongo01 ~]# systemctl restart mongod
[root@mongo01 ~]# systemctl status mongod --no-pager
● mongod.service - MongoDB Enterprise Database Server
Loaded: loaded (/etc/systemd/system/mongod.service; enabled; vendor preset: disabled)
Active: active (running) since Fri 2026-11-06 09:26:31 EST; 7min ago
Docs: https://docs.mongodb.com/manual
Process: 37776 ExecStop=/app/mongodb/7.0.43/bin/mongod --config /app/mongodb/config/mongod.conf --shutdown (code=exited, status=0/SUCCESS)
Process: 37785 ExecStart=/app/mongodb/7.0.43/bin/mongod --config /app/mongodb/config/mongod.conf (code=exited, status=0/SUCCESS)
Main PID: 37788 (mongod)
Tasks: 54 (limit: 17684)
Memory: 184.4M
CGroup: /system.slice/mongod.service
└─37788 /app/mongodb/7.0.43/bin/mongod --config /app/mongodb/config/mongod.conf
Nov 06 09:26:28 mongo01 systemd[1]: mongod.service: Succeeded.
Nov 06 09:26:28 mongo01 systemd[1]: Stopped MongoDB Enterprise Database Server.
Nov 06 09:26:28 mongo01 systemd[1]: Starting MongoDB Enterprise Database Server...
Nov 06 09:26:28 mongo01 mongod[37785]: {"t":{"$date":"2026-11-06T14:26:28.672Z"},"s":"I", "c":"CONTROL", "id":5760901, "ctx":"main","msg":"Applied --setParameter options","attr":{"ser…"value":true}}}}
Nov 06 09:26:28 mongo01 mongod[37785]: about to fork child process, waiting until server is ready for connections.
Nov 06 09:26:28 mongo01 mongod[37788]: forked process: 37788
Nov 06 09:26:31 mongo01 mongod[37785]: child process started successfully, parent exiting
Nov 06 09:26:31 mongo01 systemd[1]: Started MongoDB Enterprise Database Server.
Hint: Some lines were ellipsized, use -l to show in full.
[root@mongo01 ~]#
[root@mongo02 ~]# systemctl start mongod
[root@mongo03 ~]# systemctl start mongod
💡 Notes:
• oplogSizeMB is applied when the replica set is first initiated. To change it later, use replSetResizeOplog.
• fork: true with Type=forking in the unit file (installation guide, section 15) works with replica sets without changes.
• Use either mongoctl.sh or systemctl, not both.
Check connectivity from mongo01 (ping does not need a login):
[mongop@mongo01 ~]$ /app/mongodb/7.0.43/bin/mongosh --host mongo02 --port 27017 --eval "db.runCommand({ ping: 1 })"
{ ok: 1 }
[mongop@mongo01 ~]$ /app/mongodb/7.0.43/bin/mongosh --host mongo03 --port 27017 --eval "db.runCommand({ ping: 1 })"
{ ok: 1 }
7. Initiate the Replica Set
Run this only once, on only one server (mongo01). It tells MongoDB who the members are.
🔴 Log in first: mongo01 already has the admin user, so the localhost exception no longer applies. Running rs.initiate() without logging in fails with Unauthorized.
[mongop@mongo01 ~]$ /app/mongodb/7.0.43/bin/mongosh --host localhost -u admin --authenticationDatabase admin
Enter password: ******
Current Mongosh Log ID: 6aede6651784f524967b198d
Connecting to: mongodb://@localhost:27017/?directConnection=true&serverSelectionTimeoutMS=2000&authSource=admin&appName=mongosh+2.12.0
Using MongoDB: 7.0.43
Using Mongosh: 2.12.0
mongosh 2.14.1 is available for download: https://www.mongodb.com/try/download/shell
For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/
Enterprise test>
rs.initiate({
_id: "rs0", // must match replSetName
members: [
{ _id: 0, host: "mongo01:27017", priority: 2 }, // preferred primary
{ _id: 1, host: "mongo02:27017", priority: 1 },
{ _id: 2, host: "mongo03:27017", priority: 1 }
]
})
Enterprise test> rs.initiate({
| _id: "rs0",
| members: [
| { _id: 0, host: "mongo01:27017", priority: 2 },
| { _id: 1, host: "mongo02:27017", priority: 1 },
| { _id: 2, host: "mongo03:27017", priority: 1 }
| ]
| })
{ ok: 1 }
Enterprise rs0 [direct: secondary] test>
Enterprise rs0 [direct: secondary] test> rs.status().members.map(m => ({name: m.name, state: m.stateStr}))
[
{ name: 'mongo01:27017', state: 'PRIMARY' },
{ name: 'mongo02:27017', state: 'SECONDARY' },
{ name: 'mongo03:27017', state: 'SECONDARY' }
]
Enterprise rs0 [direct: primary] test>
Expected result: { ok: 1 }. Within a few seconds, an election runs and mongo01 is elected primary, since it has the highest priority (priority: 2). The prompt changes from rs0 [direct: secondary] test> to rs0 [direct: primary] test>. If the prompt hasn’t updated yet, press Enter once or twice.
rs.initiate() on mongo01
|
v
config saved on mongo01 --> sent to mongo02 and mongo03 (heartbeat)
|
v
mongo02 and mongo03: initial sync (copy all data from primary)
|
v
election: mongo01 gets 3 votes (priority 2 makes it the favourite)
|
v
mongo01 = PRIMARY, mongo02 and mongo03 = SECONDARY
💡 Good to know:
• priority: 2 is optional. It only makes mongo01 the preferred primary. Default priority is 1.
• Initial sync replaces the “RMAN DUPLICATE FOR STANDBY” step. MongoDB creates the copy automatically.
• The admin user is already on the primary, so you do not need to create another user.
Alternative: initiate with just one node and add the others later.
rs.initiate() // single-member set on mongo01
rs.add("mongo02:27017")
rs.add("mongo03:27017")
8. Verify and Test
Connect with the replica set connection string:
[mongop@mongo01 ~]$ /app/mongodb/7.0.43/bin/mongosh \
"mongodb://mongo01:27017,mongo02:27017,mongo03:27017/?replicaSet=rs0" \
-u admin --authenticationDatabase admin
[mongop@mongo01 ~]$ /app/mongodb/7.0.43/bin/mongosh \
> "mongodb://mongo01:27017,mongo02:27017,mongo03:27017/?replicaSet=rs0" \
> -u admin --authenticationDatabase admin
Enter password: ******
Current Mongosh Log ID: 6aede90e3d90289b52061f89
Connecting to: mongodb://@mongo01:27017,mongo02:27017,mongo03:27017/?replicaSet=rs0&authSource=admin&appName=mongosh+2.12.0
Using MongoDB: 7.0.43
Using Mongosh: 2.12.0
mongosh 2.14.1 is available for download: https://www.mongodb.com/try/download/shell
For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/
Enterprise rs0 [primary] test>
Check 1 – Member status:
rs.status().members.map(m => ({ name: m.name, state: m.stateStr, health: m.health }))
Enterprise rs0 [primary] test> rs.status().members.map(m => ({ name: m.name, state: m.stateStr, health: m.health }))
[
{ name: 'mongo01:27017', state: 'PRIMARY', health: 1 },
{ name: 'mongo02:27017', state: 'SECONDARY', health: 1 },
{ name: 'mongo03:27017', state: 'SECONDARY', health: 1 }
]
Enterprise rs0 [primary] test>
While a new member is copying its data you will see STARTUP2. Wait until it becomes SECONDARY.
Check 2 – Who is primary, the configuration, and the oplog:Check 2 – Who is primary, the configuration, and the oplog:
db.hello() // "isWritablePrimary", "primary", "hosts"
rs.conf() // members, priorities, votes, settings
rs.printReplicationInfo() // oplog size and time window
2a – db.hello(): who is primary
Enterprise rs0 [primary] test> db.hello()
{
topologyVersion: { processId: ObjectId('6aede3944cb205dabb21abc2'), counter: Long('6') },
hosts: [ 'mongo01:27017', 'mongo02:27017', 'mongo03:27017' ],
setName: 'rs0',
setVersion: 1,
isWritablePrimary: true,
secondary: false,
primary: 'mongo01:27017',
me: 'mongo01:27017',
electionId: ObjectId('7fffffff0000000000000001'),
lastWrite: {
opTime: { ts: Timestamp({ t: 1793976709, i: 1 }), t: Long('1') },
lastWriteDate: ISODate('2026-11-06T14:51:49.000Z'),
majorityOpTime: { ts: Timestamp({ t: 1793976709, i: 1 }), t: Long('1') },
majorityWriteDate: ISODate('2026-11-06T14:51:49.000Z')
},
maxBsonObjectSize: 16777216,
maxMessageSizeBytes: 48000000,
maxWriteBatchSize: 100000,
localTime: ISODate('2026-11-06T14:51:50.788Z'),
logicalSessionTimeoutMinutes: 30,
connectionId: 25,
minWireVersion: 0,
maxWireVersion: 21,
readOnly: false,
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1793976709, i: 1 }),
signature: {
hash: Binary.createFromBase64('KFyks9M892tDM3V9QUPv+qFD02s=', 0),
keyId: Long('7705068198269288454')
}
},
operationTime: Timestamp({ t: 1793976709, i: 1 })
}
💡 What this tells us:
• primary: 'mongo01:27017' and me: 'mongo01:27017' with isWritablePrimary: true: you are connected to the primary, and it is mongo01 as intended.
• hosts lists all three members, so the set knows about mongo02 and mongo03.
• setName: 'rs0' matches the replSetName in mongod.conf.
• maxWireVersion: 21 corresponds to MongoDB 7.0, which matches the 7.0.43 binary.
• electionId starting with 7fffffff...0001 means this is the first election. No failover has happened since rs.initiate().
• ok: 1 means the command succeeded.
2b – rs.conf(): configuration
Enterprise rs0 [primary] test> rs.conf()
{
_id: 'rs0',
version: 1,
term: 1,
members: [
{
_id: 0,
host: 'mongo01:27017',
arbiterOnly: false,
buildIndexes: true,
hidden: false,
priority: 2,
tags: {},
secondaryDelaySecs: Long('0'),
votes: 1
},
{
_id: 1,
host: 'mongo02:27017',
arbiterOnly: false,
buildIndexes: true,
hidden: false,
priority: 1,
tags: {},
secondaryDelaySecs: Long('0'),
votes: 1
},
{
_id: 2,
host: 'mongo03:27017',
arbiterOnly: false,
buildIndexes: true,
hidden: false,
priority: 1,
tags: {},
secondaryDelaySecs: Long('0'),
votes: 1
}
],
protocolVersion: Long('1'),
writeConcernMajorityJournalDefault: true,
settings: {
chainingAllowed: true,
heartbeatIntervalMillis: 2000,
heartbeatTimeoutSecs: 10,
electionTimeoutMillis: 10000,
catchUpTimeoutMillis: -1,
catchUpTakeoverDelayMillis: 30000,
getLastErrorModes: {},
getLastErrorDefaults: { w: 1, wtimeout: 0 },
replicaSetId: ObjectId('6aede6a94cb205dabb21ac45')
}
}
💡 What this tells us:
• version: 1 means the configuration has not changed since rs.initiate().
• mongo01 has priority: 2 and the others have priority: 1. All three have votes: 1, so any two members can form a majority.
• No hidden, delayed, or arbiter members. Every member is a normal data-bearing node.
• chainingAllowed: true lets a secondary sync from another secondary, not only from the primary. This is the default and is fine.
• electionTimeoutMillis: 10000 is the default. If the primary is unreachable for 10 seconds, a new election starts.
2c – rs.printReplicationInfo(): oplog
Enterprise rs0 [primary] test> rs.printReplicationInfo()
actual oplog size
'10240 MB'
---
configured oplog size
'10240 MB'
---
log length start to end
'822 secs (0.23 hrs)'
---
oplog first event time
'Fri Nov 06 2026 09:39:37 GMT-0500 (Eastern Standard Time)'
---
oplog last event time
'Fri Nov 06 2026 09:53:19 GMT-0500 (Eastern Standard Time)'
---
now
'Fri Nov 06 2026 09:53:21 GMT-0500 (Eastern Standard Time)'
💡 What this tells us:
• Actual oplog size equals configured size (10240 MB), so oplogSizeMB from mongod.conf was applied at initiation.
• The log length is only about 822 seconds because the set is new. The window grows as writes occur. With a 10 GB oplog and light lab traffic, it will cover days.
• The times here are in EST, while db.hello() shows UTC. 14:51 UTC is 09:51 EST, so they are consistent.
Check 3 – Write on the primary, read on a secondary:
| On mongo01 (primary) | On mongo02 (secondary) |
|---|---|
| |
The document appears on the secondary. Now try to write on the secondary:
Enterprise rs0 [direct: secondary] testdb> db.test.insertOne({ msg: "write on secondary" })
MongoServerError[NotWritablePrimary]: not primary
Enterprise rs0 [direct: secondary] testdb>
Check 4 – Replication lag (on the primary):
Enterprise rs0 [primary] testdb> rs.printSecondaryReplicationInfo()
source: mongo02:27017
{
syncedTo: 'Fri Nov 06 2026 11:39:10 GMT-0500 (Eastern Standard Time)',
replLag: '0 secs (0 hrs) behind the primary '
}
---
source: mongo03:27017
{
syncedTo: 'Fri Nov 06 2026 11:39:10 GMT-0500 (Eastern Standard Time)',
replLag: '0 secs (0 hrs) behind the primary '
}
Enterprise rs0 [primary] testdb>
Check 5 – Failover test. Stop the primary and watch another member take over:
# On mongo01
[root@mongo01 ~]# systemctl stop mongod
[root@mongo01 ~]#
# On mongo02 or mongo03 (in mongosh)
Enterprise rs0 [direct: secondary] testdb> rs.status().members.map(m => m.name + " " + m.stateStr)
[
'mongo01:27017 (not reachable/healthy)',
'mongo02:27017 PRIMARY',
'mongo03:27017 SECONDARY'
]
Enterprise rs0 [direct: secondary] testdb>
# On mongo01: start it again. It rejoins as a secondary, catches up, then takes back the primary role because it has the highest priority (priority: 2).
When mongo01 starts, it joins as a SECONDARY and catches up from the oplog. Once it is in sync, its higher priority (priority: 2) triggers an election, and it becomes the primary again. This can take a short while, so run the status check again if it still shows SECONDARY.
[root@mongo01 ~]# systemctl start mongod
[root@mongo01 ~]#
Enterprise rs0 [direct: secondary] testdb> rs.status().members.map(m => m.name + " " + m.stateStr)
[
'mongo01:27017 PRIMARY',
'mongo02:27017 SECONDARY',
'mongo03:27017 SECONDARY'
]
Enterprise rs0 [direct: secondary] testdb> Check 6 – Reboot test. Reboot one server and confirm that mongod starts by itself and the member rejoins.
Connection string for applications. List all members and the set name. The driver finds the primary and follows it after a failover:
mongodb://user:password@mongo01:27017,mongo02:27017,mongo03:27017/?replicaSet=rs0&authSource=admin
✅ The replica set is running with one primary and two secondaries.
9. Common Mistakes
• Secondaries started with old data or a different admin user. Clear /data/mongodb first (section 3).
• Keyfile permissions too open (must be 400 or 600), or not owned by mongop. mongod refuses to start.
• Different keyfile content on the servers. Members cannot authenticate to each other. Compare with md5sum.
• Different replSetName in the config than in rs.initiate().
• Running rs.initiate() without logging in as admin, or on more than one server.
• Hostnames in rs.initiate() that the other servers cannot resolve.
• Missing routing or firewall rules between the 192.168.2.x and 192.168.3.x subnets.
• Skipping the SELinux labels on mongo02 or mongo03. systemd then fails with Permission denied (installation guide, section 15). Do not disable SELinux.
• Restarting with mongoctl.sh on one server and systemctl on another. Use systemctl only.
10. Replica Set vs Data Guard
| Task | MongoDB replica set | Oracle Data Guard |
|---|---|---|
| Create the copy | Automatic initial sync | |
| What is shipped | Oplog (logical operations). Secondaries pull it. | Redo (block changes). Primary pushes it. |
| Apply process | Oplog applier threads on the secondary | Managed recovery process (MRP) |
| Add another copy | | Build a new standby, add a new LOG_ARCHIVE_DEST_n |
| Check status | | |
| Check lag | | |
| Planned role change | | |
| Automatic failover | Built in. Members vote, a new primary is elected. | Fast-Start Failover with an observer |
| Read from the copy | Yes, with read preference secondary | Active Data Guard (separate license) |
| Client finds the new primary | Driver does it, using the connection string | Role-based services, TAF / Application Continuity |
Bottom line for Oracle DBAs:
• A replica set is MongoDB’s built-in Data Guard. Setup is the same replSetName on every server, a shared keyfile, plus one rs.initiate().
• No manual standby creation. New members copy the data by themselves (initial sync).
• Use 3 members so that an election can still reach a majority when one node is down.
• Failover and the voting that decides the new primary are built in. No separate broker or observer is needed.
• Secondaries are read-only but readable, with no extra license.