---
# === IDENTITY ===
id: software/devops/docker-mongodb-replicaset/2026
canonical_question: "Docker Compose reference: MongoDB Replica Set"
aliases:
  - "How to set up MongoDB replica set with Docker Compose"
  - "Docker Compose MongoDB replication cluster"
  - "MongoDB replica set Docker development setup"
  - "docker-compose.yml MongoDB primary secondary arbiter"
  - "MongoDB rs.initiate Docker Compose"
  - "MongoDB keyfile authentication Docker"
  - "containerized MongoDB replica set"
  - "MongoDB high availability Docker Compose"
entity_type: software_reference
domain: software > devops > Docker MongoDB Replica Set
region: global
jurisdiction: global
temporal_scope: 2024-2026

# === VERIFICATION ===
last_verified: 2026-02-27
confidence: 0.93
version: 1.0
first_published: 2026-02-27

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: stable
  last_breaking_change: "MongoDB 8.0 released Aug 2024; Docker Compose V2 replaced V1 (docker compose vs docker-compose) as default in Docker Desktop 4.x (2023)"
  next_review: 2026-08-26
  change_sensitivity: low

# === CONSTRAINTS ===
constraints:
  - "Replica set names in --replSet flag MUST match the _id in rs.initiate() -- mismatch causes silent failure"
  - "Keyfile permissions MUST be 400 and owned by mongodb user (UID 999) inside the container -- MongoDB refuses to start otherwise"
  - "NEVER run a production replica set without authentication (keyFile or x509) -- any network-accessible mongod without auth is fully open"
  - "Use odd number of voting members (1, 3, 5, 7 max) to avoid split-brain during elections"
  - "Container hostnames in rs.initiate() members MUST be resolvable by all replica set members AND by connecting clients"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "Need MongoDB sharded cluster (not just replication)"
    use_instead: "software/devops/docker-mongodb-sharding/2026"
  - condition: "Need managed MongoDB (Atlas) rather than self-hosted"
    use_instead: "software/devops/mongodb-atlas-setup/2026"
  - condition: "Need standalone MongoDB without replication for quick local dev"
    use_instead: "software/devops/docker-mongodb-standalone/2026"

# === AGENT HINTS ===
inputs_needed:
  - key: "node_count"
    question: "How many replica set members do you need?"
    type: choice
    options: ["1 (dev/transactions)", "3 (standard)", "3+arbiter (budget HA)"]
  - key: "auth_required"
    question: "Do you need authentication enabled?"
    type: choice
    options: ["No (local dev only)", "Keyfile (internal auth)", "x509 (production)"]
  - key: "mongodb_version"
    question: "Which MongoDB version?"
    type: choice
    options: ["7.0 (current LTS)", "8.0 (latest)"]

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/software/devops/docker-mongodb-replicaset/2026"
suggested_citation: "Source: knowledgelib.io -- AI Knowledge Library (verified 2026-02-27)"

# === RELATED UNITS ===
related_kos:
  depends_on: []
  related_to:
    - id: "software/devops/docker-compose-networking/2026"
      label: "Docker Compose Networking Guide"
    - id: "software/devops/mongodb-backup-restore/2026"
      label: "MongoDB Backup and Restore"
  solves: []
  alternative_to:
    - id: "software/devops/mongodb-atlas-setup/2026"
      label: "MongoDB Atlas Managed Setup"
  often_confused_with:
    - id: "software/devops/docker-mongodb-sharding/2026"
      label: "Docker MongoDB Sharded Cluster"

# === SOURCES (7 authoritative sources) ===
sources:
  - id: src1
    title: "Deploy Self-Managed Replica Set With Keyfile Authentication"
    author: MongoDB
    url: https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set-with-keyfile-access-control/
    type: official_docs
    published: 2024-08-01
    reliability: authoritative
  - id: src2
    title: "mongo - Official Image | Docker Hub"
    author: Docker
    url: https://hub.docker.com/_/mongo
    type: official_docs
    published: 2025-12-01
    reliability: authoritative
  - id: src3
    title: "Deploying a MongoDB Cluster with Docker"
    author: MongoDB
    url: https://www.mongodb.com/compatibility/deploying-a-mongodb-cluster-with-docker
    type: official_docs
    published: 2024-06-01
    reliability: high
  - id: src4
    title: "Setting Up a 3-Node MongoDB Replica Set Cluster with Docker Compose"
    author: Denis Akp
    url: https://dev.to/denisakp/setting-up-a-3-node-mongodb-replica-set-cluster-with-docker-compose-50kn
    type: technical_blog
    published: 2024-10-15
    reliability: moderate_high
  - id: src5
    title: "Create a replica set in MongoDB with Docker Compose"
    author: Eric Cabrel
    url: https://blog.tericcabrel.com/mongodb-replica-set-docker-compose/
    type: technical_blog
    published: 2024-03-20
    reliability: moderate_high
  - id: src6
    title: "Creating a MongoDB Replica Set Using Docker"
    author: Soham Kamani
    url: https://www.sohamkamani.com/docker/mongo-replica-set/
    type: technical_blog
    published: 2024-05-10
    reliability: moderate_high
  - id: src7
    title: "Replica Set Configuration"
    author: MongoDB
    url: https://www.mongodb.com/docs/manual/reference/replica-configuration/
    type: official_docs
    published: 2024-08-01
    reliability: authoritative
---

# Docker Compose MongoDB Replica Set: Complete Reference

## TL;DR

- **Bottom line**: A 3-node MongoDB replica set in Docker Compose requires matching `--replSet` names, a shared keyfile for auth, a custom bridge network for DNS resolution, and a one-time `rs.initiate()` call to bootstrap the cluster.
- **Key tool/command**: `mongosh --eval "rs.initiate({_id:'rs0', members:[{_id:0,host:'mongo1:27017'},{_id:1,host:'mongo2:27017'},{_id:2,host:'mongo3:27017'}]})"`
- **Watch out for**: Hostnames in `rs.initiate()` members must be resolvable by both the containers AND your application -- using `localhost` inside containers breaks cross-node communication.
- **Works with**: MongoDB 7.0+, 8.0+; Docker Compose V2 (the `docker compose` plugin); Docker Engine 24+.

## Constraints
<!-- Agents: read this section before recommending any action from this unit.
     These are hard constraints that must not be violated. -->

- Replica set names in `--replSet` flag MUST match the `_id` in `rs.initiate()` -- mismatch causes silent failure
- Keyfile permissions MUST be 400 and owned by mongodb user (UID 999) inside the container -- MongoDB refuses to start otherwise
- NEVER run a production replica set without authentication (`keyFile` or x509) -- any network-accessible mongod without auth is fully open
- Use odd number of voting members (1, 3, 5, 7 max) to avoid split-brain during elections
- Container hostnames in `rs.initiate()` members MUST be resolvable by all replica set members AND by connecting clients

## Quick Reference

| Service | Image | Command Flags | Ports | Volumes | Key Env |
|---|---|---|---|---|---|
| mongo1 (primary) | `mongo:7.0` | `--replSet rs0 --keyFile /etc/mongo-keyfile --bind_ip_all --port 27017` | `27017:27017` | `mongo1-data:/data/db`, `mongo1-config:/data/configdb`, `./keyfile:/etc/mongo-keyfile:ro` | `MONGO_INITDB_ROOT_USERNAME`, `MONGO_INITDB_ROOT_PASSWORD` |
| mongo2 (secondary) | `mongo:7.0` | `--replSet rs0 --keyFile /etc/mongo-keyfile --bind_ip_all --port 27017` | `27018:27017` | `mongo2-data:/data/db`, `mongo2-config:/data/configdb`, `./keyfile:/etc/mongo-keyfile:ro` | Same as above |
| mongo3 (secondary) | `mongo:7.0` | `--replSet rs0 --keyFile /etc/mongo-keyfile --bind_ip_all --port 27017` | `27019:27017` | `mongo3-data:/data/db`, `mongo3-config:/data/configdb`, `./keyfile:/etc/mongo-keyfile:ro` | Same as above |
| mongo-arbiter (optional) | `mongo:7.0` | `--replSet rs0 --keyFile /etc/mongo-keyfile --bind_ip_all --port 27017` | `27020:27017` | `./keyfile:/etc/mongo-keyfile:ro` (no data volume needed) | None |
| mongo-init (one-shot) | `mongo:7.0` | Runs `mongosh` to execute `rs.initiate()` | None | `./init-replica.sh:/scripts/init-replica.sh:ro` | None |

**Replica Set Member Roles:**

| Role | Votes | Priority | Stores Data | Purpose |
|---|---|---|---|---|
| Primary | 1 | Highest (e.g., 3) | Yes | Accepts all writes; serves reads by default |
| Secondary | 1 | Lower (e.g., 1) | Yes | Replicates from primary; can serve reads with `readPreference` |
| Arbiter | 1 | 0 | No | Participates in elections only; breaks ties |
| Hidden | 1 | 0 | Yes | Invisible to clients; used for analytics/backup |
| Delayed | 1 | 0 | Yes | Lags behind primary by configured seconds; disaster recovery |

**Connection String Formats:**

| Context | Connection String |
|---|---|
| From host (no auth) | `mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0` |
| From host (with auth) | `mongodb://admin:password@localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0&authSource=admin` |
| From Docker network | `mongodb://admin:password@mongo1:27017,mongo2:27017,mongo3:27017/?replicaSet=rs0&authSource=admin` |
| With TLS | Append `&tls=true&tlsCAFile=/path/to/ca.pem` |
| Node.js driver | `mongodb://admin:password@mongo1:27017,mongo2:27017,mongo3:27017/mydb?replicaSet=rs0&authSource=admin&w=majority` |

## Decision Tree

```
START: What is your use case?
├── Local development (need transactions/change streams)?
│   ├── YES → Single-node replica set (1 member, simplest setup)
│   └── NO ↓
├── Development/staging with HA testing?
│   ├── YES → 3-node replica set (primary + 2 secondaries)
│   └── NO ↓
├── Production with budget constraints?
│   ├── YES → 2 data nodes + 1 arbiter (saves storage, still has quorum)
│   └── NO ↓
├── Production with full redundancy?
│   ├── YES → 3-node replica set with keyfile auth + named volumes + resource limits
│   └── NO ↓
├── Need read scaling across regions?
│   ├── YES → 5 or 7 members with priorities + readPreference=secondary
│   └── NO ↓
└── DEFAULT → 3-node replica set with keyfile authentication
```

## Step-by-Step Guide

### 1. Generate the keyfile for internal authentication

The keyfile is used for inter-node authentication within the replica set. All members must share the same keyfile. [src1]

```bash
# Generate a random 756-byte base64-encoded key
openssl rand -base64 756 > ./keyfile

# Set restrictive permissions (MongoDB requires 400)
chmod 400 ./keyfile

# On Linux, change ownership to match the MongoDB container user
# The mongo Docker image runs as UID 999 (mongodb user)
sudo chown 999:999 ./keyfile
```

**Verify**: `ls -la ./keyfile` --> expected: `-r--------  1 999 999  1024 ... keyfile`

### 2. Create the Docker Compose file

Define three MongoDB services on a shared network with the keyfile mounted read-only. [src2] [src4]

```yaml
# docker-compose.yml — MongoDB 7.0 Replica Set (3 nodes + auth)
name: mongodb-rs

services:
  mongo1:
    image: mongo:7.0
    container_name: mongo1
    hostname: mongo1
    command: ["--replSet", "rs0", "--keyFile", "/etc/mongo-keyfile", "--bind_ip_all", "--port", "27017"]
    ports:
      - "27017:27017"
    volumes:
      - mongo1-data:/data/db
      - mongo1-config:/data/configdb
      - ./keyfile:/etc/mongo-keyfile:ro
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD:-changeme}
    networks:
      - mongo-cluster
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping').ok", "--quiet"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    restart: unless-stopped

  mongo2:
    image: mongo:7.0
    container_name: mongo2
    hostname: mongo2
    command: ["--replSet", "rs0", "--keyFile", "/etc/mongo-keyfile", "--bind_ip_all", "--port", "27017"]
    ports:
      - "27018:27017"
    volumes:
      - mongo2-data:/data/db
      - mongo2-config:/data/configdb
      - ./keyfile:/etc/mongo-keyfile:ro
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD:-changeme}
    networks:
      - mongo-cluster
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping').ok", "--quiet"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    restart: unless-stopped

  mongo3:
    image: mongo:7.0
    container_name: mongo3
    hostname: mongo3
    command: ["--replSet", "rs0", "--keyFile", "/etc/mongo-keyfile", "--bind_ip_all", "--port", "27017"]
    ports:
      - "27019:27017"
    volumes:
      - mongo3-data:/data/db
      - mongo3-config:/data/configdb
      - ./keyfile:/etc/mongo-keyfile:ro
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD:-changeme}
    networks:
      - mongo-cluster
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping').ok", "--quiet"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    restart: unless-stopped

  mongo-init:
    image: mongo:7.0
    container_name: mongo-init
    depends_on:
      mongo1:
        condition: service_healthy
      mongo2:
        condition: service_healthy
      mongo3:
        condition: service_healthy
    volumes:
      - ./init-replica.sh:/scripts/init-replica.sh:ro
      - ./keyfile:/etc/mongo-keyfile:ro
    entrypoint: ["bash", "/scripts/init-replica.sh"]
    networks:
      - mongo-cluster
    restart: "no"

networks:
  mongo-cluster:
    driver: bridge

volumes:
  mongo1-data:
  mongo1-config:
  mongo2-data:
  mongo2-config:
  mongo3-data:
  mongo3-config:
```

**Verify**: `docker compose config` --> should output valid YAML with no errors.

### 3. Create the replica set initialization script

This script connects to the primary candidate and runs `rs.initiate()` with the member list. [src1] [src5]

```bash
#!/bin/bash
# init-replica.sh — Initialize MongoDB replica set
# Waits for primary candidate, then initiates the replica set

echo "Waiting for MongoDB nodes to be ready..."
sleep 10

echo "Initializing replica set..."
mongosh --host mongo1:27017 -u admin -p "${MONGO_PASSWORD:-changeme}" --authenticationDatabase admin --eval '
  rs.initiate({
    _id: "rs0",
    members: [
      { _id: 0, host: "mongo1:27017", priority: 3 },
      { _id: 1, host: "mongo2:27017", priority: 2 },
      { _id: 2, host: "mongo3:27017", priority: 1 }
    ]
  });
'

echo "Waiting for replica set to stabilize..."
sleep 5

echo "Replica set status:"
mongosh --host mongo1:27017 -u admin -p "${MONGO_PASSWORD:-changeme}" --authenticationDatabase admin --eval 'rs.status().members.forEach(m => print(m.name, m.stateStr))'

echo "Replica set initialization complete."
```

**Verify**: After `docker compose up -d`, run `docker logs mongo-init` --> expected: member list with `PRIMARY` and `SECONDARY` states.

### 4. Start the cluster and verify

Bring up all services and check the replica set status. [src3]

```bash
# Start all services
docker compose up -d

# Wait for initialization to complete (check mongo-init logs)
docker compose logs -f mongo-init

# Connect to the primary and verify status
docker exec -it mongo1 mongosh -u admin -p changeme --authenticationDatabase admin --eval "rs.status()"
```

**Verify**: `rs.status().members` should show 3 members -- one `PRIMARY` and two `SECONDARY`.

### 5. Create application database and user

After the replica set is running, create a dedicated database user for your application. [src1]

```javascript
// Connect to primary via mongosh
// mongosh -u admin -p changeme --authenticationDatabase admin

// Switch to admin database
use admin;

// Create application user with readWrite on specific database
db.createUser({
  user: "appuser",
  pwd: "appsecret",
  roles: [
    { role: "readWrite", db: "myapp" },
    { role: "readWrite", db: "myapp_test" }
  ]
});

// Verify user creation
db.getUser("appuser");
```

**Verify**: `mongosh -u appuser -p appsecret --authenticationDatabase admin myapp --eval "db.test.insertOne({ok:1})"` --> expected: `{ acknowledged: true }`

### 6. Test write concern and read preference

Verify that replication is working by writing with majority write concern and reading from secondaries. [src7]

```javascript
// Connect as appuser
// mongosh -u appuser -p appsecret --authenticationDatabase admin myapp

// Insert with write concern majority (waits for replication)
db.test.insertOne(
  { msg: "replicated", ts: new Date() },
  { writeConcern: { w: "majority", wtimeout: 5000 } }
);

// Read from secondary (set read preference)
db.getMongo().setReadPref("secondary");
db.test.find();
```

**Verify**: Document appears on secondary reads; `rs.printReplicationInfo()` shows replication lag < 1 second.

## Code Examples

### Single-Node Replica Set (Minimal Development Setup)

```yaml
# docker-compose.yml — Single-node replica set for local dev
# Use case: Need transactions or change streams without full cluster
services:
  mongodb:
    image: mongo:7.0
    container_name: mongodb
    command: ["--replSet", "rs0", "--bind_ip_all"]
    ports:
      - "27017:27017"
    volumes:
      - mongo-data:/data/db
    healthcheck:
      test: >
        mongosh --eval "try{rs.status().ok}catch(e){rs.initiate({_id:'rs0',members:[{_id:0,host:'localhost:27017'}]}).ok}"
      interval: 10s
      timeout: 10s
      retries: 5
      start_period: 30s
    restart: unless-stopped

volumes:
  mongo-data:
```

### Node.js: Connection with Retry Logic

```javascript
// Input:  MongoDB replica set connection string
// Output: Connected MongoClient with automatic failover
const { MongoClient } = require('mongodb');  // ^6.0.0

const uri = 'mongodb://admin:changeme@mongo1:27017,mongo2:27017,mongo3:27017/?replicaSet=rs0&authSource=admin';

const client = new MongoClient(uri, {
  // Replica set connection options
  readPreference: 'secondaryPreferred',
  w: 'majority',
  wtimeoutMS: 10000,
  retryWrites: true,
  retryReads: true,
  serverSelectionTimeoutMS: 5000,
  connectTimeoutMS: 10000,
});

async function main() {
  await client.connect();
  const db = client.db('myapp');
  // Verify replica set connectivity
  const status = await db.admin().command({ replSetGetStatus: 1 });
  console.log('Connected to replica set:', status.set);
}
```

### Python: Connection with PyMongo

```python
# Input:  MongoDB replica set connection string
# Output: Connected client with automatic failover
from pymongo import MongoClient  # pymongo >= 4.6.0

uri = (
    "mongodb://admin:changeme@mongo1:27017,mongo2:27017,mongo3:27017/"
    "?replicaSet=rs0&authSource=admin"
    "&readPreference=secondaryPreferred"
    "&w=majority&wtimeoutMS=10000"
    "&retryWrites=true&retryReads=true"
)

client = MongoClient(uri, serverSelectionTimeoutMS=5000)
db = client["myapp"]

# Verify replica set connectivity
status = db.admin.command("replSetGetStatus")
print(f"Connected to replica set: {status['set']}")
print(f"Members: {[m['name'] for m in status['members']]}")
```

### With Arbiter Node (Budget HA)

> Full script: [with-arbiter-node-budget-ha.yml](scripts/with-arbiter-node-budget-ha.yml) (60 lines)

```yaml
# docker-compose.yml — 2 data nodes + 1 arbiter
# Use case: High availability with reduced storage costs
services:
  mongo1:
    image: mongo:7.0
# ... (see full script)
```

## Anti-Patterns

### Wrong: Using localhost in replica set member hostnames

```yaml
# BAD -- localhost only resolves within a single container
# Other replica set members cannot reach each other via localhost
command: ["--replSet", "rs0", "--bind_ip", "localhost"]
# rs.initiate with localhost:
# members: [{ _id: 0, host: "localhost:27017" }]
```

### Correct: Use container hostnames on a shared network

```yaml
# GOOD -- container hostnames resolve via Docker DNS
command: ["--replSet", "rs0", "--bind_ip_all"]
# rs.initiate with container names:
# members: [
#   { _id: 0, host: "mongo1:27017" },
#   { _id: 1, host: "mongo2:27017" },
#   { _id: 2, host: "mongo3:27017" }
# ]
```

### Wrong: Keyfile with permissive permissions

```bash
# BAD -- MongoDB refuses to start with world-readable keyfile
chmod 644 ./keyfile
# Error: "permissions on /etc/mongo-keyfile are too open"
```

### Correct: Restrictive keyfile permissions with correct ownership

```bash
# GOOD -- only owner can read, owned by mongodb user (UID 999)
chmod 400 ./keyfile
sudo chown 999:999 ./keyfile
```

### Wrong: Mismatched replica set names

```yaml
# BAD -- replSet name in command does not match rs.initiate _id
command: ["--replSet", "myRS"]
# Then in mongosh:
# rs.initiate({ _id: "rs0", members: [...] })
# Result: silent failure, nodes never join
```

### Correct: Consistent replica set name everywhere

```yaml
# GOOD -- same name in command flag and rs.initiate
command: ["--replSet", "rs0"]
# In mongosh:
# rs.initiate({ _id: "rs0", members: [...] })
```

### Wrong: No healthcheck or init container

```yaml
# BAD -- no mechanism to initialize the replica set
# Requires manual mongosh connection after every restart
services:
  mongo1:
    image: mongo:7.0
    command: ["--replSet", "rs0"]
    # Missing: healthcheck or init container to call rs.initiate()
```

### Correct: Healthcheck-based or init container initialization

```yaml
# GOOD -- healthcheck auto-initializes on first run
healthcheck:
  test: >
    mongosh --eval "try{rs.status().ok}catch(e){rs.initiate({_id:'rs0',members:[{_id:0,host:'mongo1:27017'}]}).ok}"
  interval: 10s
  timeout: 10s
  retries: 5
```

### Wrong: Even number of voting members

```javascript
// BAD -- 2 voting members cannot achieve majority if one goes down
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "mongo1:27017" },
    { _id: 1, host: "mongo2:27017" }
  ]
});
// If mongo1 fails, mongo2 cannot elect itself (needs 2/2 = majority)
```

### Correct: Odd number of voting members

```javascript
// GOOD -- 3 members: majority is 2, survives 1 failure
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "mongo1:27017" },
    { _id: 1, host: "mongo2:27017" },
    { _id: 2, host: "mongo3:27017" }
  ]
});
```

## Common Pitfalls

- **Keyfile ownership inside container**: The mongo Docker image runs as UID 999. If the keyfile is owned by root on the host, MongoDB inside the container cannot read it. Fix: `sudo chown 999:999 ./keyfile` before starting containers. [src1]
- **MONGO_INITDB vars only work on first run**: `MONGO_INITDB_ROOT_USERNAME` and `MONGO_INITDB_ROOT_PASSWORD` are only processed when `/data/db` is empty. If volumes already have data, these variables are silently ignored. Fix: Delete volumes with `docker compose down -v` to re-initialize. [src2]
- **Host cannot resolve container hostnames**: If your application runs on the host (not in Docker), it cannot resolve `mongo1`, `mongo2`, `mongo3`. Fix: Add entries to `/etc/hosts` (`127.0.0.1 mongo1 mongo2 mongo3`) or use `localhost:27017,localhost:27018,localhost:27019` in the connection string. [src5]
- **rs.initiate() fails during startup**: MongoDB needs time to start accepting connections. Calling `rs.initiate()` too early fails with "connection refused". Fix: Use `depends_on` with `condition: service_healthy` or add `sleep 10` before init script. [src4]
- **Election timeout after primary stops**: Default `electionTimeoutMillis` is 10 seconds. Secondaries wait this long before starting an election. During this window, writes fail. Fix: Adjust `settings.electionTimeoutMillis` in replica config if faster failover is needed, but keep it above 5000ms to avoid flapping. [src7]
- **Bind IP not set to all interfaces**: By default, mongod binds to `localhost` only. Containers on the Docker network cannot reach each other. Fix: Always use `--bind_ip_all` or `--bind_ip 0.0.0.0` in the command. [src3]
- **Missing write concern for critical data**: Default write concern is `w:1` (acknowledged by primary only). If the primary crashes before replication, data is lost. Fix: Use `w: "majority"` for important writes. [src7]
- **Windows Docker keyfile permissions**: Docker on Windows cannot enforce Linux file permissions via volume mounts. Fix: Copy keyfile into a custom image with correct permissions, or use `--keyFile` with a file created by the entrypoint script. [src2]

## Diagnostic Commands

```bash
# Check replica set status (from inside a container)
docker exec -it mongo1 mongosh -u admin -p changeme --authenticationDatabase admin --eval "rs.status()"

# Show current replica set configuration
docker exec -it mongo1 mongosh -u admin -p changeme --authenticationDatabase admin --eval "rs.conf()"

# Check replication lag on each member
docker exec -it mongo1 mongosh -u admin -p changeme --authenticationDatabase admin --eval "rs.printReplicationInfo()"

# Identify which node is primary
docker exec -it mongo1 mongosh -u admin -p changeme --authenticationDatabase admin --eval "rs.isMaster().primary"

# Check oplog size and utilization
docker exec -it mongo1 mongosh -u admin -p changeme --authenticationDatabase admin --eval "rs.printReplicationInfo()"

# Verify all members are healthy
docker exec -it mongo1 mongosh -u admin -p changeme --authenticationDatabase admin --eval "rs.status().members.map(m => ({name: m.name, state: m.stateStr, health: m.health}))"

# Test connection string from host
mongosh "mongodb://admin:changeme@localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0&authSource=admin" --eval "db.runCommand({ping:1})"

# Check container health status
docker compose ps

# View MongoDB logs for a specific node
docker compose logs mongo1 --tail 50

# Force step-down of primary (for failover testing)
docker exec -it mongo1 mongosh -u admin -p changeme --authenticationDatabase admin --eval "rs.stepDown(60)"
```

## Version History & Compatibility

| MongoDB Version | Docker Tag | Status | Key Changes | Compose Notes |
|---|---|---|---|---|
| 8.0 | `mongo:8.0` | Current | New query optimizer, improved sharding | Same compose config as 7.0; fully compatible |
| 7.0 | `mongo:7.0` | Current LTS | Compound wildcard indexes, auto-encryption improvements | Recommended for production Docker deployments |
| 6.0 | `mongo:6.0` | Supported until Aug 2025 | Queryable encryption, cluster-to-cluster sync | Uses `mongosh` (not legacy `mongo` shell) |
| 5.0 | `mongo:5.0` | EOL Oct 2024 | Time series collections, versioned API | Last version with legacy `mongo` shell |
| 4.4 | `mongo:4.4` | EOL Feb 2024 | Hidden indexes, refinable shard keys | Uses `mongo` shell (not `mongosh`) |

**Docker Compose compatibility:**

| Compose Version | Command | Status | Notes |
|---|---|---|---|
| V2 (plugin) | `docker compose` | Current | Integrated into Docker CLI; use `depends_on.condition` |
| V1 (standalone) | `docker-compose` | Deprecated | Does not support `service_healthy` in `depends_on` |

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Local development needing transactions or change streams | Simple CRUD dev without transactions | Standalone MongoDB (no replica set) |
| CI/CD pipeline integration testing | Production deployment on cloud infrastructure | MongoDB Atlas or Kubernetes operator |
| Staging environment that mirrors production HA | Single-server deployment with no failover needs | Standalone MongoDB with periodic backups |
| Learning MongoDB replication and failover | Need global distribution across regions | MongoDB Atlas global clusters |
| Testing application behavior during primary failover | Running on systems with < 4 GB RAM | Single-node replica set (1 member) |

## Important Caveats

- Docker volumes persist data across container restarts, but `docker compose down -v` deletes all data -- never use `-v` in production without backups
- The `MONGO_INITDB_ROOT_USERNAME`/`PASSWORD` environment variables only initialize on the first run when `/data/db` is empty; changing them after initial setup has no effect
- On macOS and Windows, Docker Desktop uses a Linux VM, so volume performance is significantly slower than native Linux; consider using named volumes instead of bind mounts for `/data/db`
- MongoDB replica set elections take 10-12 seconds by default; during this window your application must handle write failures gracefully with retry logic
- The official `mongo` Docker image runs as root by default but switches to UID 999 for the mongod process; ensure file permissions account for this
- In Docker Swarm or Kubernetes, container hostnames and DNS resolution work differently -- the compose-based approach in this guide is for single-host or Docker Compose-specific deployments

## Related Units
<!-- Generated from related_kos frontmatter -->

- [Docker Compose Networking Guide](/software/devops/docker-compose-networking/2026)
- [MongoDB Backup and Restore](/software/devops/mongodb-backup-restore/2026)
- [MongoDB Atlas Managed Setup](/software/devops/mongodb-atlas-setup/2026)
- [Docker MongoDB Sharded Cluster](/software/devops/docker-mongodb-sharding/2026)
