Configuration makes or breaks MongoDB deployments: it shapes security, durability, performance, and day-2 operations. This guide highlights common MongoDB configuration mistakes, shows safe ways to fix them, and provides verification and rollback steps you can trust. The focus is practical: concrete checks, small reversible changes, and clear signals that confirm the fix worked.
Who this is for: developers, DevOps consultants, and technical startup teams who run MongoDB for APIs (for example, Node.js and Express) or internal services.
What you get: a short inventory step, a safe configuration path with examples, verification and diagnostics, failure modes and recovery, and an operations checklist you can reuse.
Version and Environment Inventory
Before you change anything, capture a short inventory so you know what is safe to alter online, what needs a restart, and what requires staged rollout.
Collect:
- MongoDB edition and version
- Topology: standalone, replica set, or sharded cluster
- Storage engine and data path
- Auth and TLS status
- Resource limits (file descriptors), CPU/RAM/disk profile, filesystem type
Quick commands:
- Server version:
mongod --version(shell) ordb.version()in mongosh - Topology:
rs.status()for replica sets,sh.status()for sharded - Config source:
db.adminCommand({getCmdLineOpts: 1})to see parsed config - Auth status: try
db.runCommand({connectionStatus: 1}) - TLS on/off: check
db.adminCommand({getParameter: 1, tlsMode: 1})or logs for TLS
Prerequisites for safe work:
- A recent, tested backup or snapshot of the data and
/etc/mongod.conf(or your config path) - Maintenance window sized to the most disruptive step (restarts, reconfigs)
- Access to all nodes and the ability to stop/start the service
- A small pilot scope first (for example, one secondary) before cluster-wide changes
Safe Configuration Path
This section lists high-impact mistakes, how to detect them, and how to fix them safely with concrete steps.
1. Open network binding and no authentication
Symptoms:
- MongoDB is reachable from untrusted networks
- You can run admin commands without credentials
Check:
use admin
// Shows parsed net.bindIp and security.authorization
db.adminCommand({getCmdLineOpts: 1})
Look for net.bindIp and security.authorization. If bindIp includes 0.0.0.0 or authorization is disabled, fix it.
Safe fix:
- If you do not have any users yet, bootstrap an admin account using the localhost exception, then enable auth.
- Bind only to required interfaces (loopback plus a private address) or a load balancer VIP.
Example steps:
# 1. Create the first admin user (only if no users exist yet)
mongosh --host 127.0.0.1 --port 27017
use admin
db.createUser({
user: 'siteRootAdmin',
pwd: 'REPLACE_WITH_STRONG_PASSWORD',
roles: [ { role: 'root', db: 'admin' } ]
})
Edit the config (example: /etc/mongod.conf):
net:
port: 27017
bindIp: 127.0.0.1,10.0.0.10
security:
authorization: enabled
Restart the service and verify that unauthenticated access is blocked and the admin login works.
2. TLS disabled or switching to requireTLS too abruptly
Symptoms:
- In-transit data not encrypted
- Clients break when you flip to
requireTLSwithout a transition period
Check:
use admin
db.adminCommand({getParameter: 1, tlsMode: 1})
// Or check logs for 'TLS' during startup
Safe migration to TLS:
- Stage 1:
transitionToTLS(accepts both TLS and non-TLS) - Stage 2:
requireTLSonce all clients use TLS
Config example:
net:
tls:
mode: transitionToTLS
certificateKeyFile: /etc/ssl/mongodb.pem
CAFile: /etc/ssl/ca.pem
After all clients are updated and verified, change mode to requireTLS and restart.
3. Too-small replication oplog
Symptoms:
- Secondaries fall behind during peak write bursts
- Rollbacks during elections
Check window:
rs.printReplicationInfo()
If the oplog window is only minutes to an hour on a busy system, resize it.
Safe resize (one member at a time):
- Choose a secondary, ensure it is healthy and caught up
- Resize on that node, observe steady state, repeat for other secondaries, then primary
Command on the chosen node (example value for 10 GB):
use admin
db.adminCommand({ replSetResizeOplog: 1, size: 10240 })
rs.printReplicationInfo()
Ensure the oplog window grows as expected and replication remains healthy.
4. Risky write concern and journaling mismatch
Symptoms:
- Using
w:1andj: falseon critical writes risks acknowledged-but-lost data in power loss - Inconsistent defaults across services
Check current default RW concern:
use admin
db.adminCommand({ getDefaultRWConcern: 1 })
Safer cluster-wide default:
use admin
db.adminCommand({
setDefaultRWConcern: 1,
defaultWriteConcern: { w: 'majority', j: true, wtimeout: 0 }
})
Application override example (Node.js):
const client = await MongoClient.connect(uri, {
writeConcern: { w: 'majority', j: true, wtimeoutMS: 5000 }
});
5. WiredTiger cache mis-sized
Symptoms:
- Too small: high page faults, cache eviction pressure, slow queries
- Too large: memory pressure on OS and risk of OOM
Check:
use admin
db.serverStatus().wiredTiger.cache // review bytes currently in cache and eviction stats
Safe approach:
- Start with default cache sizing
- If customizing, pick a conservative value and observe
Config example (for a 32 GB server):
storage:
wiredTiger:
engineConfig:
cacheSizeGB: 14
Restart, then observe memory and eviction metrics for several hours.
6. Journaling disabled
Symptoms:
- Faster perceived writes but at risk of data loss on crash
Check:
use admin
db.serverStatus().wiredTiger.transaction // check durability stats
Safer config:
storage:
journal:
enabled: true
Restart to apply.
7. File descriptor limits too low
Symptoms:
- Connection spikes fail with EMFILE (Too many open files)
Check limits:
cat /proc/$(pidof mongod)/limits | grep 'open files'
Increase via systemd override:
sudo systemctl edit mongod
Add:
[Service]
LimitNOFILE=64000
Then:
sudo systemctl daemon-reload && sudo systemctl restart mongod
8. Replica set priorities and hidden members misconfigured
Symptoms:
- Elections pick a poorly placed primary
- Hidden or delayed members accidentally become eligible
Check and fix:
var cfg = rs.conf()
// Review cfg.members[*].priority, .hidden, .votes
// Example: ensure analytics secondary is hidden and non-voting
cfg.members[2].hidden = true
cfg.members[2].priority = 0
cfg.members[2].votes = 0
rs.reconfig(cfg)
Apply only one logical change set at a time and confirm the new config with rs.conf().
Quick Reference Table
| Mistake | Symptom | Quick check | Safer state |
|---|---|---|---|
| bindIp open, no auth | Remote unauth access | getCmdLineOpts | Bind to private IPs, enable auth |
| TLS off | Cleartext traffic | tlsMode or logs | transitionToTLS -> requireTLS |
| Small oplog | Secondaries lag | rs.printReplicationInfo | Resize oplog per node |
| w:1, j: false | Risky acks | getDefaultRWConcern | majority + j: true |
| Cache oversized | OS memory pressure | serverStatus WT cache | Default or measured size |
| Journal off | Crash data loss risk | serverStatus | Journal enabled |
| Low NOFILE | EMFILE errors | /proc/<pid>/limits | LimitNOFILE >= 64000 |
| Bad priorities | Wrong primary | rs.conf | Explicit priorities/hidden |
Verification and Diagnostics
After each change, verify with simple, observable signals. Favor checks that prove the intended state and catch regressions.
Security and access
- From an untrusted host, connection should fail:
mongosh 'mongodb://MONGO_HOST:27017' --eval 'db.runCommand({ping:1})'
# Expect authentication or TLS error when blocked
- From an admin account, basic admin works:
mongosh 'mongodb://siteRootAdmin:***@MONGO_HOST/admin?authSource=admin' --eval 'db.runCommand({ping:1})'
- TLS handshake succeeds:
openssl s_client -connect MONGO_HOST:27017 -tls1_2 -servername MONGO_HOST < /dev/null 2>/dev/null | head -5
Replication and durability
- Healthy replication:
rs.status().members.map(m => ({name: m.name, stateStr: m.stateStr, optime: m.optimeDate}))
rs.printSecondaryReplicationInfo()
- Oplog window reasonable for your write volume:
rs.printReplicationInfo()
- Default write concern set:
use admin
db.adminCommand({ getDefaultRWConcern: 1 })
Performance and resources
- Cache and eviction stable:
var c = db.serverStatus().wiredTiger.cache; ({usedGB:(c['bytes currently in the cache']/(1024**3)).toFixed(1), evictions: c['eviction server evicted pages']})
- File descriptors:
cat /proc/$(pidof mongod)/limits | grep 'open files'
- Logs are quiet on warnings after restart:
sudo journalctl -u mongod -n 200 --no-pager | egrep -i 'error|warn|tls|auth|oplog'
Expected results:
- Security: unauthenticated attempts fail; authenticated ones succeed; TLS is negotiated when required
- Replication: all members SECONDARY or PRIMARY as intended; little to no replication lag; oplog window sized to comfortably exceed peak replication delay
- Durability: default write concern shows majority + j: true for critical workloads
- Resources: cache usage under control; system memory headroom preserved; NOFILE high enough to avoid EMFILE errors
Failure Modes and Recovery
Plan for the ways changes can fail and script the rollback.
Bind IP and auth
- Failure: enable auth before creating an admin user leads to lockout
- Recovery: revert the last config change and restart; if necessary during maintenance, temporarily disable authorization in the config, restart on an isolated network, create the admin user, then re-enable authorization and restart
TLS mode changes
- Failure: switching straight to requireTLS drops legacy clients
- Recovery: roll back to transitionToTLS, update clients, then move to requireTLS again
Oplog resize
- Failure: shrinking too far causes secondaries to fall behind and need initial sync
- Recovery: increase oplog size and allow catch-up; if a secondary falls off the oplog window, perform an initial sync on that member
Default write concern
- Failure: more write timeouts after raising durability
- Recovery: lower wtimeout, consider moving from majority to a lower w in non-critical paths, or revert the default with:
use admin
db.adminCommand({ setDefaultRWConcern: 1, defaultWriteConcern: { w: 1, j: false, wtimeout: 0 } })
Then tune per-collection or per-API path in the client driver.
WiredTiger cache
- Failure: oversizing triggers OOM or swapping
- Recovery: revert to previous cacheSizeGB, restart, and watch memory pressure
File descriptors
- Failure: service will not start after a bad systemd override
- Recovery: remove or fix the override file, run
systemctl daemon-reload, then start again
Replica set reconfig
- Failure: setting all priorities to 0 prevents a primary election
- Recovery: correct the config and run
rs.reconfig(cfg)from a node with quorum; if cluster is stuck, carefully consult the reconfig process with a majority of nodes online
Always verify recovery
- Confirm the service starts cleanly
- Confirm expected auth/TLS modes
- Confirm replication health
- Confirm application-level reads and writes work within SLOs
Operations Checklist
Use this short, repeatable checklist for configuration work.
Plan
- Define the change, scope, and measurable success signals
- Capture inventory: version, topology, current config
- Take a tested backup of data and the config file
- Pick a pilot node (prefer a secondary)
Implement (one change set at a time)
- Prepare exact config diff and commands
- Apply to the pilot node
- Restart only if required by the parameter
- Observe logs and metrics for at least 15-30 minutes or long enough to cover peak behavior
Verify
- Run verification commands for security, replication, and resources
- Compare metrics to baseline and success criteria
- If pilot is stable, roll out sequentially to remaining nodes
Rollback
- Keep a copy of the previous config file per node
- Know the single command to revert the change (for example, setDefaultRWConcern, restore bindIp)
- Verify service health and application SLOs after rollback
Record
- Update runbooks and docs with final config and rationale
- Note the verification evidence and any follow-ups
Change Impact Table
| Config item | Online change | Requires restart | Suggested rollout |
|---|---|---|---|
| bindIp | No | Yes | One node at a time in maintenance window |
| authorization | No | Yes | Create admin first, then enable, one node at a time |
| tlsMode | No | Yes | transitionToTLS -> requireTLS with client validation |
| oplog size | Yes (modern versions) | No | One member at a time, primary last |
| default RW concern | Yes | No | Apply cluster-wide, monitor timeouts |
| WT cache size | No | Yes | Pilot on secondary, then others |
| NOFILE limit | No | Service restart | Staggered restarts |
| rs priorities | Yes | No | Single reconfig with quorum |
Conclusion
MongoDB does well with deliberate, observable configuration changes. Start with a narrow pilot, verify in a way that mirrors your real workload, and keep rollback simple. Use the checks and examples here to harden security, improve durability, and reduce avoidable operational noise. As you adopt changes, document the exact diffs, commands, and signals that prove success so the next change is even safer and faster.