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:27017MongoServerError: bad auth : authentication failedMongooseServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017Or one of these variations:
MongoServerSelectionError: connection <monitor> to 127.0.0.1:27017 closedMongoNetworkError: failed to connect to server [localhost:27017] on first connectMongooseServerSelectionError: Could not connect to any servers in your MongoDB Atlas cluster.MongoParseError: Invalid connection stringThese 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 needmongodb+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 (usuallyadmin). If your connection string doesn’t specifyauthSource, 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 mongodCheck the status:
sudo systemctl status mongodIf it’s not enabled to start on boot:
sudo systemctl enable mongodmacOS (Homebrew):
brew services start mongodb-communityCheck the status:
brew services list | grep mongodbWindows:
Open Services (Win+R, type services.msc), find MongoDB Server, right-click, and select Start.
Or from an elevated Command Prompt:
net start MongoDBVerify 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 27017If 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.logCommon 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/mydbWith authentication:
mongodb://myuser:mypassword@localhost:27017/mydb?authSource=adminMongoDB Atlas (cloud)
Use mongodb+srv://:
mongodb+srv://myuser:mypassword@cluster0.abc123.mongodb.net/mydb?retryWrites=true&w=majorityCommon mistakes:
- Using
mongodb://with an Atlas hostname. Atlas requiresmongodb+srv://because it uses DNS SRV records to discover replica set members. - Using
mongodb+srv://withlocalhost. SRV lookups don’t work forlocalhost. Usemongodb://for local servers. - Missing the database name after the hostname. Without it, MongoDB defaults to the
testdatabase. - Special characters in the password. Characters like
@,:,/,%, and#must be URL-encoded.p@ss:wordbecomesp%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:
mongoshThen 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=adminIn 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
- Log in to MongoDB Atlas.
- Go to Network Access under Security in the left sidebar.
- Click Add IP Address.
- Click Add Current IP Address, or enter your IP manually.
- 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/0for 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/mydbLinux:
docker run --add-host=host.docker.internal:host-gateway myappThen 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:
- mongoThe 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_healthyDocker 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 -dWarning: 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.netOr:
Error: querySrv ENOTFOUND _mongodb._tcp.cluster0.abc123.mongodb.netCheck 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.netIf 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.8or1.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:
- Go to your cluster in Atlas.
- Click Connect → Drivers.
- 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=adminFix 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=trueNote: 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 certificateThis 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=rs0Running 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 localhostThen 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 connectionsTo accept connections from other machines:
net:
port: 27017
bindIp: 0.0.0.0 # Accepts connections from all interfacesRestart MongoDB after changing this:
sudo systemctl restart mongodWarning: 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.confsecurity:
authorization: enabledIf it is, you must include credentials in your connection string:
mongodb://myuser:mypassword@localhost:27017/mydb?authSource=adminIPv6 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:27017Fix by using 127.0.0.1 explicitly instead of localhost:
mongodb://127.0.0.1:27017/mydbOr configure MongoDB to listen on both:
net:
bindIp: 127.0.0.1,::1Firewall 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 --reloadSecurity 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 --validateCommon 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.1Environment 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.