MongoDB Users & Authentication
MongoDB is a NoSQL database (a database that stores data as flexible JSON-like documents instead of rigid tables). By default, older MongoDB packages started with no authentication at all — meaning anyone who could reach the network port could read, change, or delete every document. This page shows you how to create an admin user, turn authentication on, restart the service, and connect with credentials. Getting this right is one of the most important security tasks a DevOps engineer can do, because an exposed MongoDB is a favourite target for ransomware bots.
Critical warning: MongoDB historically shipped with authentication OFF. Thousands of databases have been wiped by automated attackers who simply scanned the internet for open MongoDB ports. Never put MongoDB on a public network without (1) authentication enabled and (2) a firewall locking down the port. We cover both below.
Why authentication matters
Authentication answers the question “who are you?”. Authorization answers “what are you allowed to do?”. MongoDB needs both. Without authentication, MongoDB does not ask for a username or password — it trusts every connection. That is fine for a quick local experiment, but dangerous the moment the server is reachable by anyone else.
There is a chicken-and-egg problem here. You cannot create users on a database that requires login if no users exist yet. So MongoDB has a feature called the localhost exception: when auth is enabled but zero users exist, you are allowed to connect from the same machine once, purely to create the very first admin user. After that user exists, the exception closes.
When to enable auth (and when not)
| Situation | Enable auth? |
|---|---|
| Production server, any environment | Always |
| Server reachable from the internet or office LAN | Always |
| A throwaway database inside Docker on your laptop, bound to localhost only | Optional, but recommended habit |
| CI pipeline spinning up a temporary container, no network exposure | Optional |
The safe default is: turn it on everywhere. It costs you nothing and protects you from a single misconfigured firewall rule ruining your week.
Step 1: Create the first admin user
Make sure MongoDB is installed and running first (see Installing MongoDB). At this point auth is still OFF, so connect with the mongosh shell (the modern MongoDB command-line client):
mongosh
Switch to the special admin database and create a user with the userAdminAnyDatabase role. This role can create and manage other users but cannot read your application data — that separation is good security practice.
use admin
db.createUser({
user: "mongoAdmin",
pwd: passwordPrompt(),
roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
})
Using passwordPrompt() instead of typing the password inline keeps your password out of the shell history. You will be asked to type it interactively.
Output:
Enter password
*********
{ ok: 1 }
Type exit to leave the shell.
Step 2: Enable authorization in mongod.conf
Now tell MongoDB to actually require login. On Ubuntu the config file lives at /etc/mongod.conf. Open it with a text editor:
sudo nano /etc/mongod.conf
Find the security: line (it may be commented out with a #) and set it like this. YAML is indentation-sensitive, so use exactly two spaces before authorization:
security:
authorization: enabled
While you are in this file, check the net: section. By default modern packages bind only to 127.0.0.1 (localhost), which is safe. Only widen bindIp if a remote app genuinely needs access — and pair that with a firewall:
net:
port: 27017
bindIp: 127.0.0.1
Save and exit (in nano, press Ctrl+O, Enter, then Ctrl+X).
Step 3: Restart and lock the firewall
Restart the service so the new config takes effect, using systemctl (the tool that manages services on Ubuntu):
sudo systemctl restart mongod
sudo systemctl status mongod
Output:
● mongod.service - MongoDB Database Server
Loaded: loaded (/usr/lib/systemd/system/mongod.service; enabled)
Active: active (running) since Mon 2026-06-15 10:42:11 UTC; 3s ago
If you must allow remote access, restrict the port to a known IP with ufw (Ubuntu’s simple firewall). Never run ufw allow 27017 to the whole world:
sudo ufw allow from 203.0.113.10 to any port 27017 proto tcp
Step 4: Connect with credentials
Try connecting without a password — you should now be refused any privileged action:
mongosh --username mongoAdmin --authenticationDatabase admin
The --authenticationDatabase admin flag tells MongoDB which database holds the user account. This is a common stumbling block: the user lives in admin, even if you later work in a different database. You will be prompted for the password, then dropped into the shell.
Output:
Enter password: *********
Current Mongosh Log ID: 67e0...
Connecting to: mongodb://127.0.0.1:27017/
test>
Built-in roles
MongoDB ships with ready-made roles so you rarely need custom ones. Grant the least privilege that gets the job done — an app user should not have admin powers.
| Role | Scope | What it grants |
|---|---|---|
read | One database | Read-only access to that database |
readWrite | One database | Read and modify data in that database |
dbAdmin | One database | Manage indexes, stats, and collections (not data) |
userAdmin | One database | Create and manage users in that database |
readWriteAnyDatabase | All databases | Read/write across every database |
userAdminAnyDatabase | All databases | Manage all users everywhere |
clusterAdmin | Cluster | Full cluster/replica-set administration |
root | Everything | Superuser — avoid for day-to-day use |
To create a scoped application user (after logging in as the admin), give it readWrite on just its own database:
use admin
db.createUser({
user: "shopApp",
pwd: passwordPrompt(),
roles: [ { role: "readWrite", db: "shopDB" } ]
})
Your application then connects with a URI (connection string) that includes the credentials and the auth database:
mongodb://shopApp:[email protected]:27017/shopDB?authSource=admin
Gotcha: Store this connection string in an environment variable or a secrets manager — never commit it to Git. A leaked URI hands an attacker your whole database.
Best Practices
- Enable
authorization: enabledon every server, including development, so the habit is automatic and a firewall slip cannot expose you. - Bind to
127.0.0.1unless remote access is truly required, and gate any open port withufw allow from <trusted-ip>. - Grant least privilege — give app users
readWriteon a single database, notrootor*AnyDatabaseroles. - Use a separate admin user for user management and separate app users per service, so credentials can be rotated independently.
- Use
passwordPrompt()in the shell to keep passwords out of history, and use strong, unique passwords for each user. - Keep connection strings in secrets, never in source control or container images.
- Patch promptly — run a current MongoDB release, since older versions have known unauthenticated exploits.