Skip to content
DevOps devops databases 5 min read

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)

SituationEnable auth?
Production server, any environmentAlways
Server reachable from the internet or office LANAlways
A throwaway database inside Docker on your laptop, bound to localhost onlyOptional, but recommended habit
CI pipeline spinning up a temporary container, no network exposureOptional

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.

RoleScopeWhat it grants
readOne databaseRead-only access to that database
readWriteOne databaseRead and modify data in that database
dbAdminOne databaseManage indexes, stats, and collections (not data)
userAdminOne databaseCreate and manage users in that database
readWriteAnyDatabaseAll databasesRead/write across every database
userAdminAnyDatabaseAll databasesManage all users everywhere
clusterAdminClusterFull cluster/replica-set administration
rootEverythingSuperuser — 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: enabled on every server, including development, so the habit is automatic and a firewall slip cannot expose you.
  • Bind to 127.0.0.1 unless remote access is truly required, and gate any open port with ufw allow from <trusted-ip>.
  • Grant least privilege — give app users readWrite on a single database, not root or *AnyDatabase roles.
  • 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.
Last updated June 15, 2026
Was this helpful?