Fix: MongoServerError: bad auth / MongoNetworkError: connect ECONNREFUSED / MongooseServerSelectionError

The Error

You try to connect to MongoDB and get one of these:

MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017
MongoServerError: bad auth : authentication failed
MongooseServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017

Or one of these variations:

MongoServerSelectionError: connection <monitor> to 127.0.0.1:27017 closed
MongoNetworkError: failed to connect to server [localhost:27017] on first connect
MongooseServerSelectionError: Could not connect to any servers in your MongoDB Atlas cluster.
MongoParseError: Invalid connection string

These all boil down to three problems: MongoDB isn’t reachable, your credentials are wrong, or your connection string is malformed.

Why This Happens

MongoDB listens for connections on port 27017 by default. When your client can’t reach it, you get ECONNREFUSED. When it reaches the server but authentication fails, you get bad auth. When the driver can’t select any server from the topology, you get ServerSelectionError.

Common causes:

  • MongoDB isn’t running. The service was never started, crashed, or was stopped during an OS update.
  • Wrong connection string format. Using mongodb:// when you need mongodb+srv:// (Atlas), or vice versa.
  • Wrong username or password. The credentials don’t match, or you’re authenticating against the wrong database.
  • Missing authSource. MongoDB stores user credentials in a specific database (usually admin). If your connection string doesn’t specify authSource, authentication fails silently.
  • Atlas network access / IP whitelist. MongoDB Atlas rejects connections from IP addresses not in its allow list.
  • Docker networking. Your app container is trying to reach MongoDB on localhost, which resolves to the container itself.
  • DNS resolution failure. mongodb+srv:// relies on DNS SRV records. If DNS can’t resolve the hostname, the connection fails.
  • TLS/SSL mismatch. The server requires TLS but your client isn’t using it, or your client is sending TLS to a server that doesn’t expect it.
  • Replica set misconfiguration. The replica set name in your connection string doesn’t match the server’s configuration.
  • Connection pool exhaustion. All connections in the pool are in use and the driver can’t open new ones.

Fix 1: Start MongoDB

The most common cause. MongoDB isn’t running.

Linux (systemd):

sudo systemctl start mongod

Check the status:

sudo systemctl status mongod

If it’s not enabled to start on boot:

sudo systemctl enable mongod

macOS (Homebrew):

brew services start mongodb-community

Check the status:

brew services list | grep mongodb

Windows:

Open Services (Win+R, type services.msc), find MongoDB Server, right-click, and select Start.

Or from an elevated Command Prompt:

net start MongoDB

Verify it’s listening:

mongosh --eval "db.runCommand({ ping: 1 })"

If mongosh isn’t installed, use the legacy shell:

mongo --eval "db.runCommand({ ping: 1 })"

Or check the port directly:

# Linux / macOS
ss -tlnp | grep 27017

# Windows (PowerShell)
netstat -an | findstr 27017

If nothing is listening on 27017, MongoDB isn’t running. Check the logs:

# Linux
sudo tail -50 /var/log/mongodb/mongod.log

# macOS (Homebrew)
tail -50 /opt/homebrew/var/log/mongodb/mongo.log

Common startup failures:

  • Data directory doesn’t exist. MongoDB refuses to start without its data directory. Create it:
sudo mkdir -p /var/lib/mongodb
sudo chown -R mongodb:mongodb /var/lib/mongodb
  • Lock file left behind after a crash. Remove the stale lock file:
sudo rm /var/lib/mongodb/mongod.lock
sudo -u mongodb mongod --repair --dbpath /var/lib/mongodb
sudo systemctl start mongod
  • Disk full. MongoDB won’t start if it can’t write to the data or journal directories. Free up space first.

Fix 2: Fix Your Connection String Format

MongoDB uses two connection string formats, and they are not interchangeable.

Local MongoDB / self-hosted

Use mongodb://:

mongodb://localhost:27017/mydb

With authentication:

mongodb://myuser:mypassword@localhost:27017/mydb?authSource=admin

MongoDB Atlas (cloud)

Use mongodb+srv://:

mongodb+srv://myuser:mypassword@cluster0.abc123.mongodb.net/mydb?retryWrites=true&w=majority

Common mistakes:

  • Using mongodb:// with an Atlas hostname. Atlas requires mongodb+srv:// because it uses DNS SRV records to discover replica set members.
  • Using mongodb+srv:// with localhost. SRV lookups don’t work for localhost. Use mongodb:// for local servers.
  • Missing the database name after the hostname. Without it, MongoDB defaults to the test database.
  • Special characters in the password. Characters like @, :, /, %, and # must be URL-encoded. p@ss:word becomes p%40ss%3Aword:
// Wrong -- the @ in the password breaks parsing
const uri = "mongodb://user:p@ssword@localhost:27017/mydb";

// Right -- URL-encode special characters
const uri = "mongodb://user:p%40ssword@localhost:27017/mydb";

You can use encodeURIComponent() in JavaScript to encode the password:

const password = encodeURIComponent("p@ss:word");
const uri = `mongodb://user:${password}@localhost:27017/mydb`;

Fix 3: Fix Authentication (bad auth)

MongoServerError: bad auth : authentication failed means the server is reachable but your credentials are wrong.

Check your username and password

Connect to MongoDB without authentication first (if your server allows it), or use a known-good admin account:

mongosh

Then verify the user exists:

use admin
db.getUsers()

If the user doesn’t exist, create it:

use admin
db.createUser({
  user: "myuser",
  pwd: "mypassword",
  roles: [{ role: "readWrite", db: "mydb" }]
})

Specify authSource

This is the most overlooked cause of bad auth. MongoDB stores user credentials in a specific database. If your user was created in the admin database but your connection string doesn’t include authSource=admin, MongoDB looks for the user in the target database and fails.

// Wrong -- MongoDB looks for the user in "mydb"
mongodb://myuser:mypassword@localhost:27017/mydb

// Right -- tells MongoDB to authenticate against "admin"
mongodb://myuser:mypassword@localhost:27017/mydb?authSource=admin

In Mongoose:

mongoose.connect('mongodb://myuser:mypassword@localhost:27017/mydb', {
  authSource: 'admin'
});

Check which database the user was created in

// Check in admin
use admin
db.getUsers()

// Check in the target database
use mydb
db.getUsers()

If the user exists in mydb, set authSource=mydb. If it exists in admin, set authSource=admin.

Reset a user’s password

use admin
db.changeUserPassword("myuser", "newpassword")

Fix 4: Fix MongoDB Atlas Network Access

Atlas rejects all connections from IP addresses not in the network access list. You see:

MongooseServerSelectionError: Could not connect to any servers in your MongoDB Atlas cluster.

Add your IP address

  1. Log in to MongoDB Atlas.
  2. Go to Network Access under Security in the left sidebar.
  3. Click Add IP Address.
  4. Click Add Current IP Address, or enter your IP manually.
  5. Click Confirm.

It takes 1-2 minutes for the change to propagate.

Allow access from anywhere (development only)

Add 0.0.0.0/0 to the access list. This allows connections from any IP.

Warning: Never use 0.0.0.0/0 in production. It exposes your database to the internet. Use specific IPs or VPC peering instead.

Your IP changed

If you’re on a home or mobile network, your IP changes frequently. Either:

  • Add the new IP each time it changes.
  • Use 0.0.0.0/0 for development.
  • Set up a VPN with a static IP for production.

Atlas cluster is paused or deleted

Free-tier (M0) clusters pause after 60 days of inactivity. Go to the Atlas dashboard and check if your cluster is active. Paused clusters show a Resume button.

Fix 5: Fix Docker Networking

If your app is inside a Docker container, localhost inside the container refers to the container itself, not the host machine or other containers.

Connecting to MongoDB on the host from a container

Docker Desktop (macOS/Windows):

mongodb://host.docker.internal:27017/mydb

Linux:

docker run --add-host=host.docker.internal:host-gateway myapp

Then use host.docker.internal in your connection string.

Connecting between containers (docker-compose)

Use the service name as the hostname:

services:
  mongo:
    image: mongo:7
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: secret
    ports:
      - "27017:27017"

  app:
    build: .
    environment:
      MONGODB_URI: mongodb://root:secret@mongo:27017/mydb?authSource=admin
    depends_on:
      - mongo

The hostname is mongo (the service name), not localhost.

MongoDB container isn’t ready yet

If your app starts before MongoDB finishes initializing, the connection fails. Add a health check:

services:
  mongo:
    image: mongo:7
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: secret
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
      interval: 5s
      timeout: 5s
      retries: 5

  app:
    build: .
    depends_on:
      mongo:
        condition: service_healthy

Docker MongoDB password was set on first run

Like MySQL, the official MongoDB Docker image only sets MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD on first initialization. If you change these values after data already exists in the volume, the old credentials remain.

Fix by removing the volume and reinitializing:

docker compose down -v
docker compose up -d

Warning: This deletes all data in the MongoDB volume. Export your data first with mongodump if needed.

For more on Docker networking issues, see Fix: ERR_CONNECTION_REFUSED on localhost and Fix: Docker Permission Denied.

Fix 6: Fix DNS Resolution (SRV Records)

mongodb+srv:// connection strings rely on DNS SRV and TXT records. If DNS resolution fails, you get:

MongooseServerSelectionError: getaddrinfo ENOTFOUND cluster0.abc123.mongodb.net

Or:

Error: querySrv ENOTFOUND _mongodb._tcp.cluster0.abc123.mongodb.net

Check DNS resolution

# Check the SRV record
nslookup -type=SRV _mongodb._tcp.cluster0.abc123.mongodb.net

# Or with dig
dig SRV _mongodb._tcp.cluster0.abc123.mongodb.net

If the SRV lookup fails:

  • Your DNS server doesn’t support SRV records. Some corporate or restrictive networks block SRV queries. Try a public DNS like 8.8.8.8 or 1.1.1.1.
  • The hostname is wrong. Copy the connection string directly from the Atlas dashboard. Don’t type it manually.
  • VPN or proxy is interfering. Disconnect your VPN and try again.

Fall back to the standard connection string

If SRV resolution is blocked, get the standard connection string from Atlas:

  1. Go to your cluster in Atlas.
  2. Click ConnectDrivers.
  3. Under the connection string, look for the option to show the standard format (without SRV).

The standard format lists each replica set member explicitly:

mongodb://myuser:mypassword@cluster0-shard-00-00.abc123.mongodb.net:27017,cluster0-shard-00-01.abc123.mongodb.net:27017,cluster0-shard-00-02.abc123.mongodb.net:27017/mydb?ssl=true&replicaSet=atlas-abc123-shard-0&authSource=admin

Fix 7: Fix TLS/SSL Issues

MongoDB Atlas and many production deployments require TLS. If your client isn’t using TLS, or the certificates don’t match, the connection fails silently and eventually times out into a ServerSelectionError.

Atlas requires TLS

Atlas connections always require TLS. Make sure your connection string includes tls=true or ssl=true (they’re aliases):

mongodb+srv://user:pass@cluster0.abc123.mongodb.net/mydb?retryWrites=true&w=majority&tls=true

Note: mongodb+srv:// enables TLS by default. You only need to add tls=true explicitly if you’re using the standard mongodb:// format with Atlas.

Self-hosted MongoDB with TLS

If your self-hosted MongoDB requires TLS but your client isn’t sending it:

mongoose.connect('mongodb://localhost:27017/mydb', {
  tls: true,
  tlsCAFile: '/path/to/ca.pem',
  tlsCertificateKeyFile: '/path/to/client.pem'
});

Certificate errors

MongoServerSelectionError: unable to verify the first certificate

This means the client can’t verify the server’s TLS certificate. Options:

// Option 1: Provide the CA certificate
mongoose.connect(uri, {
  tls: true,
  tlsCAFile: '/path/to/ca-certificate.crt'
});

// Option 2: Disable certificate validation (development ONLY)
mongoose.connect(uri, {
  tls: true,
  tlsAllowInvalidCertificates: true
});

Warning: Never disable certificate validation in production. It makes you vulnerable to man-in-the-middle attacks.

Fix 8: Fix Replica Set Configuration

If your connection string specifies a replica set name that doesn’t match the server’s configuration, the driver silently refuses to use that server.

Check the replica set name

Connect to the server and run:

rs.status()

Look for the set field:

{
  "set": "rs0",
  ...
}

Your connection string must match:

mongodb://localhost:27017/mydb?replicaSet=rs0

Running a single-node replica set locally

MongoDB requires a replica set for transactions and change streams. To run a single-node replica set for development:

mongod --replSet rs0 --dbpath /var/lib/mongodb --bind_ip localhost

Then initialize it:

mongosh --eval "rs.initiate()"

Or in Docker:

services:
  mongo:
    image: mongo:7
    command: ["--replSet", "rs0", "--bind_ip_all"]
    ports:
      - "27017:27017"

After the container starts:

docker exec -it mongo mongosh --eval "rs.initiate()"

Fix 9: Fix Mongoose Connection Options

Mongoose wraps the MongoDB Node.js driver and adds its own layer of connection handling. Misconfigured Mongoose options cause MongooseServerSelectionError even when the MongoDB server is healthy.

Basic Mongoose connection

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/mydb')
  .then(() => console.log('Connected'))
  .catch(err => console.error('Connection error:', err));

Increase the server selection timeout

The default serverSelectionTimeoutMS is 30 seconds. If MongoDB is slow to start (common in Docker), increase it:

mongoose.connect('mongodb://localhost:27017/mydb', {
  serverSelectionTimeoutMS: 60000 // 60 seconds
});

Handle connection events

mongoose.connection.on('error', err => {
  console.error('MongoDB connection error:', err);
});

mongoose.connection.on('disconnected', () => {
  console.log('MongoDB disconnected');
});

Deprecated options

If you see warnings about deprecated options, remove them. These options are no longer needed in Mongoose 6+ and the MongoDB Node.js driver 4+:

// Remove these -- they do nothing in modern versions and may cause warnings
{
  useNewUrlParser: true,      // removed
  useUnifiedTopology: true,   // removed
  useCreateIndex: true,       // removed
  useFindAndModify: false     // removed
}

Just pass the URI and any needed auth or TLS options.

Still Not Working?

Connection pool exhaustion

If your app connects fine initially but starts failing under load with ServerSelectionError or timeouts, you may be exhausting the connection pool.

The default pool size is 100 connections per MongoDB server. If your app opens connections faster than it releases them, the pool fills up.

Check for connection leaks:

// Monitor the pool
mongoose.connection.on('connected', () => {
  console.log('Pool size:', mongoose.connection.client.options.maxPoolSize);
});

Increase the pool size if needed:

mongoose.connect('mongodb://localhost:27017/mydb', {
  maxPoolSize: 200,
  minPoolSize: 10
});

But first, investigate whether your code is leaking connections. Common causes:

  • Opening a new connection for every request instead of reusing one.
  • Not closing connections in serverless functions (AWS Lambda, Vercel).
  • Long-running operations holding connections open.

For serverless environments, cache the connection:

let cached = global.mongoose;

if (!cached) {
  cached = global.mongoose = { conn: null, promise: null };
}

async function connectDB() {
  if (cached.conn) return cached.conn;

  if (!cached.promise) {
    cached.promise = mongoose.connect(process.env.MONGODB_URI);
  }

  cached.conn = await cached.promise;
  return cached.conn;
}

MongoDB is binding to 127.0.0.1 only

By default, MongoDB binds to 127.0.0.1. If you’re connecting from another machine or from a Docker container using the host’s network IP, the connection is refused.

Check mongod.conf:

# /etc/mongod.conf
net:
  port: 27017
  bindIp: 127.0.0.1  # Only accepts local connections

To accept connections from other machines:

net:
  port: 27017
  bindIp: 0.0.0.0  # Accepts connections from all interfaces

Restart MongoDB after changing this:

sudo systemctl restart mongod

Warning: Never bind to 0.0.0.0 without enabling authentication. An unauthenticated MongoDB exposed to the internet will be compromised within hours.

MongoDB authentication is enabled but you’re connecting without credentials

If MongoDB was started with --auth or has security.authorization: enabled in mongod.conf, every connection must authenticate. Connecting without credentials gives bad auth or a silent failure followed by MongooseServerSelectionError.

Check if auth is enabled:

grep -i authorization /etc/mongod.conf
security:
  authorization: enabled

If it is, you must include credentials in your connection string:

mongodb://myuser:mypassword@localhost:27017/mydb?authSource=admin

IPv6 vs IPv4

On some systems, localhost resolves to ::1 (IPv6) instead of 127.0.0.1 (IPv4). MongoDB may only be listening on IPv4.

MongoNetworkError: connect ECONNREFUSED ::1:27017

Fix by using 127.0.0.1 explicitly instead of localhost:

mongodb://127.0.0.1:27017/mydb

Or configure MongoDB to listen on both:

net:
  bindIp: 127.0.0.1,::1

Firewall blocking port 27017

A firewall may be dropping connections before they reach MongoDB.

# UFW (Ubuntu)
sudo ufw allow 27017/tcp

# firewalld (RHEL/Fedora)
sudo firewall-cmd --add-port=27017/tcp --permanent
sudo firewall-cmd --reload

Security note: Only open port 27017 to trusted networks. Use VPC peering or private endpoints for Atlas, and SSH tunnels for self-hosted remote access.

mongod.conf has a YAML formatting error

MongoDB’s config file uses YAML. A tab character instead of spaces, or incorrect indentation, causes MongoDB to fail on startup without a clear error.

Validate the config:

mongod --config /etc/mongod.conf --validate

Common YAML mistakes:

# Wrong -- tabs instead of spaces
net:
	port: 27017

# Wrong -- missing space after colon
net:
  port:27017

# Right
net:
  port: 27017
  bindIp: 127.0.0.1

Environment variable not loaded

Your connection string is stored in .env but the app can’t read it. The MONGODB_URI variable is undefined, and Mongoose tries to connect to the default mongodb://localhost:27017/test.

Make sure you’re loading your environment variables before connecting:

require('dotenv').config(); // Must be called before mongoose.connect()

mongoose.connect(process.env.MONGODB_URI);

If the variable is still undefined, see Fix: Environment Variable Is Undefined.


Related: For other database connection issues, see Fix: PostgreSQL Connection Refused and Fix: Access Denied for User (MySQL). For Redis connection errors, see Fix: Redis WRONGTYPE Operation. If your app can’t read the database connection string from environment variables, see Fix: Environment Variable Is Undefined. For Docker networking issues, see Fix: ERR_CONNECTION_REFUSED on localhost and Fix: Docker Permission Denied.

Related Articles

Fix: Error: Process completed with exit code 1 (GitHub Actions)

How to fix 'Process completed with exit code 1' and other GitHub Actions workflow failures. Covers reading logs, exit codes, Node.js/Python/Docker step failures, secrets and environment variables, GITHUB_TOKEN permissions, checkout issues, caching, timeouts, self-hosted runners, matrix strategy, and artifacts.

Fix: WRONGTYPE Operation against a key holding the wrong kind of value (Redis)

How to fix Redis errors: WRONGTYPE Operation against a key holding the wrong kind of value, MISCONF Redis is configured to save RDB snapshots, OOM command not allowed, READONLY You can't write against a read only replica, and other common Redis errors. Covers key type mismatches, disk issues, memory limits, eviction policies, connection problems, and serialization.

Fix: SSL certificate problem: unable to get local issuer certificate

How to fix 'SSL certificate problem: unable to get local issuer certificate', 'CERT_HAS_EXPIRED', 'ERR_CERT_AUTHORITY_INVALID', and 'self signed certificate in certificate chain' errors in Git, curl, Node.js, Python, Docker, and more. Covers CA certificates, corporate proxies, Let's Encrypt, certificate chains, and self-signed certs.

Fix: ERR_CONNECTION_REFUSED (localhost refused to connect)

How to fix 'ERR_CONNECTION_REFUSED', 'localhost refused to connect', and 'This site can't be reached' errors when accessing localhost in Chrome, Firefox, and Edge. Covers dev servers, port issues, 0.0.0.0 vs 127.0.0.1, Docker port mapping, WSL2, firewalls, and more.