Every year, thousands of MongoDB databases are found exposed on the internet with no password, their data copied or held to ransom. Almost all of those incidents come from a handful of avoidable mistakes: authentication switched off, the server listening on a public address, and applications connecting as an all-powerful admin user.
A secure deployment combines several layers. Authentication makes every client prove who it is. Authorisation with roles limits what each user can do, following the principle of least privilege: the web application can read and write its own database, the reporting tool can only read, and only administrators can manage users. Network controls make the database reachable only from your application servers. Encryption protects data travelling over the network and stored on disk. Auditing records who did what.
MongoDB Atlas applies many of these protections by default, but you still choose users, roles and network access. In this lesson you'll create users with built-in and custom roles, restrict network access, understand encryption options, and protect your application code from NoSQL injection.
Authentication and users
On a self-managed server, turn on access control in the configuration file:
# mongod.conf
security:
authorization: enabled
net:
bindIp: 127.0.0.1,10.0.1.12Then create users. Users are defined in a database, often admin, and receive roles:
use admin
db.createUser({ user: 'siteAdmin', pwd: passwordPrompt(), roles: ['userAdminAnyDatabase'] })
use shop
db.createUser({ user: 'shopApp', pwd: passwordPrompt(), roles: [{ role: 'readWrite', db: 'shop' }] })passwordPrompt()asks for the password instead of typing it into your shell history.- Applications authenticate with the user in their connection string:
mongodb://shopApp:...@db1:27017/shop?authSource=shop.
Built-in and custom roles
| Role | Can |
|---|---|
read | Read all collections in one database |
readWrite | Read and write data in one database |
dbAdmin | Manage indexes and statistics, not data |
userAdmin | Manage users and roles in one database |
clusterMonitor | Read monitoring information |
backup, restore | Run backup and restore tools |
root | Everything, for emergencies only |
When built-in roles are too broad, create a custom role with exactly the privileges needed, such as reading orders and updating only orders.status-related collections:
db.createRole({
role: 'orderClerk',
privileges: [{ resource: { db: 'shop', collection: 'orders' }, actions: ['find', 'update'] }],
roles: []
})Network, encryption and auditing
- Bind MongoDB only to private network interfaces, and use firewalls, security groups or Atlas IP access lists so only application servers can connect.
- Use TLS so connections are encrypted; Atlas requires it.
- Encryption at rest protects data files and backups; Atlas encrypts storage by default.
- Client-side field level encryption and Queryable Encryption encrypt sensitive fields, such as national ID numbers, in the application, so even database administrators can't read them.
- Auditing (MongoDB Enterprise and Atlas) records authentication, user changes and data access.
- Keep connection strings and passwords in a secret manager or environment variables, and rotate them if they leak.
MongoDB Operations Syntax
Security commands
db.createUser({ user: 'app', pwd: passwordPrompt(), roles: [{ role: 'readWrite', db: 'shop' }] })
db.grantRolesToUser('app', [{ role: 'read', db: 'reports' }])
db.revokeRolesFromUser('app', [{ role: 'read', db: 'reports' }])
db.changeUserPassword('app', passwordPrompt())
db.dropUser('oldScript')
db.getUsers()
db.createRole({ role: 'statusUpdater', privileges: [{ resource: { db: 'shop', collection: 'orders' }, actions: ['find', 'update'] }], roles: [] })
db.runCommand({ connectionStatus: 1 }).authInfoMongoDB Operations Summary
- Enable authentication and access control, and never expose MongoDB to the public internet.
- db.createUser creates users with roles; passwordPrompt keeps passwords out of shell history.
- Follow least privilege: read, readWrite and narrow custom roles instead of admin roles for apps.
- Restrict network access, use TLS, and encrypt data at rest and sensitive fields.
- Keep credentials in secrets management, audit activity, and validate input to prevent NoSQL injection.
MongoDB Operations Examples
Each example shows the code, the output it produces and what each part does.
Creating application users with least privilege
use shop
db.createUser({ user: 'shopApi', pwd: 'use-a-long-random-secret', roles: [{ role: 'readWrite', db: 'shop' }] })
db.createUser({ user: 'reporting', pwd: 'another-long-random-secret', roles: [{ role: 'read', db: 'shop' }] })
db.getUsers().users.map(u => `${u.user}: ${u.roles.map(r => r.role + '@' + r.db).join(', ')}`)switched to db shop
{ ok: 1 }
{ ok: 1 }
[ 'reporting: read@shop', 'shopApi: readWrite@shop' ]Line-by-line explanation
- Line 2The API can read and write the shop database, and nothing else.
- Line 3The reporting tool can only read; it can't change or delete anything.
- Lines 2 to 3In real use, generate long random passwords and enter them with passwordPrompt().
- Line 4getUsers lists users and their roles in the current database.
What a read-only user can't do
// connected as reporting
db.runCommand({ connectionStatus: 1 }).authInfo.authenticatedUsers
db.orders.countDocuments()
try {
db.orders.deleteMany({})
} catch (e) {
print(`${e.codeName}: ${e.message.split(' on ')[0]}`)
}[ { user: 'reporting', db: 'shop' } ]
1204
Unauthorized: not authorizedLine-by-line explanation
- Line 2connectionStatus shows which user this session is authenticated as.
- Line 3Reading is allowed by the read role.
- Line 5Deleting isn't, so even a mistaken or malicious command can't remove data.
- Line 7Error code name Unauthorized means the role lacks that action.
A custom role and NoSQL injection
use shop
db.createRole({
role: 'orderStatusUpdater',
privileges: [{ resource: { db: 'shop', collection: 'orders' }, actions: ['find', 'update'] }],
roles: []
})
db.createUser({ user: 'warehouse', pwd: 'long-random-secret', roles: ['orderStatusUpdater'] })
const userInput = { $ne: null }
db.accounts.insertMany([{ email: 'ada@example.com' }, { email: 'ben@example.com' }]).acknowledged
db.accounts.find({ email: userInput }).toArray().length
db.accounts.find({ email: String(userInput) }).toArray().lengthswitched to db shop
{ ok: 1 }
{ ok: 1 }
true
2
0Line-by-line explanation
- Lines 2 to 6A custom role grants only find and update on the orders collection.
- Line 7The warehouse system can mark orders as shipped, but can't touch customers or delete anything.
- Line 9Imagine this object arrived in a JSON request body instead of an email string.
- Line 11Used directly, the operator matches every account: NoSQL injection.
- Line 12Forcing the value to a string, or validating its type first, makes it harmless.
Common MongoDB Operations Mistakes
Leaving authentication off
mongod --bind_ip_all # no auth, listening on every interface: open to the internetmongod --auth --bind_ip 127.0.0.1,10.0.1.12 --tlsMode requireTLS ...Applications using an admin account
mongodb://root:password@db1:27017/?authSource=admin // a bug or leak exposes every databasemongodb://shopApi:...@db1:27017/shop?authSource=shop // readWrite on shop onlyPasswords in shell history and source code
db.createUser({ user: 'app', pwd: 'Summer2026!', roles: ['readWrite'] }) // saved in history, easy to guessdb.createUser({ user: 'app', pwd: passwordPrompt(), roles: [{ role: 'readWrite', db: 'shop' }] })MongoDB Operations in Real Projects
Security in production deployments
Teams run MongoDB on private networks or Atlas with IP access lists or private endpoints, require TLS, and store credentials in AWS Secrets Manager, Vault or similar tools. Each service has its own database user with a narrow role, credentials rotate automatically, and audit logs feed security monitoring. Sensitive fields such as health data or identity numbers use client-side field level encryption.
MongoDB Operations FAQ
How do I enable authentication in MongoDB?
Create an administrative user first, then set security.authorization: enabled in mongod.conf, or start mongod with --auth, and restart the server. From then on, clients must log in, and they can only do what their roles allow. In the official Docker image, setting MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD creates a root user and enables authentication for you.
How do I change a MongoDB user's password?
Switch to the database where the user was created and run db.changeUserPassword('shopApp', passwordPrompt()). db.updateUser can change the password and roles together. Update the connection string in your application's secret store at the same time, or the app will fail to authenticate on its next connection.
How do I list the users in a MongoDB database?
Run db.getUsers() in the database where the users were created, or show users in mongosh. Each entry shows the user's name, database and roles, never the password. To see users from every database, query db.getSiblingDB('admin').system.users as an administrator.
What does authSource mean in a MongoDB connection string?
authSource names the database where the user was created, which is where MongoDB checks the credentials. If you created the user in admin but connect to the shop database, add ?authSource=admin, otherwise authentication fails even with the right password. When it's omitted, the database in the connection string's path is used, or admin if there isn't one.
Is MongoDB secure by default?
Modern versions bind to localhost only by default, so a fresh server isn't reachable from other machines. Access control, however, is off until you enable it, which is why exposing a server on a public address without authentication has led to many data leaks. Enable authentication, use TLS, restrict network access, and give each application a user with only the roles it needs.
MongoDB Operations Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the role so the app can read and write the shop database.
db.createUser({ user: 'app', pwd: passwordPrompt(), roles: [{ role: '', db: 'shop' }] })
What does least privilege mean?
Which built-in role can read but not change data?
Why use passwordPrompt() when creating users?
How does NoSQL injection happen?
MongoDB Operations Quiz
5 questions to check what you learned.
What should be enabled so every client must prove who it is?
- Sharding
- Authentication (access control)
- Replication
- Profiling
What does TLS protect?
- Data travelling over the network between clients and servers
- Data on disk
- Passwords in code
- Indexes
What's a custom role used for?
- Granting exactly the actions needed on specific resources
- Renaming users
- Creating databases
- Backups only
Who should have the root role?
- Every application
- Almost nobody; it's for emergencies
- Reporting tools
- All developers
What does client-side field level encryption add?
- Faster queries
- Automatic backups
- Shorter passwords
- Sensitive fields are encrypted by the application, so even database administrators can't read them