Creating Role-Based Access Control in MongoDB

MongoDB provides user access through role-based controls, including many built-in roles that can be assigned to users. The two most well-known controls are the read and read/write roles, however, sometimes, they’re not as granular as we’d like them to be.

I recently had a chance to explore the user-defined roles in introduced in MongoDB version 2.6. In this article, we’ll go over the MongoDB user-defined roles and define some custom roles that you might find useful.


1. Create Roles in MongoDB:

Creating a user-defined role in MongoDB is quite simple. You can use createRole command to create a new role, and the generic create role syntax is as follows:

   createRole: "<role name>",
   privileges: [{
      resource: { <resource> },
      actions: [ "<action>",] },
   roles: [
      { role: "<role>", db: "<database>" } | "<role>",],
   writeConcern: <write concern document>

Before running the createRole command, make sure you switch to the database you want to create the role in as they’ll only be defined in the database in which they were created.  If you want to create a role that grants access to more than one database, then it will need to be created on the admin database.

Let’s go over the major components of the create role syntax.

1.1  Role Privileges:

Create permissions for a user-defined role by adding a privilege and defining your actions and resources:

Privilege Actions:

  • Actions are a set of operations that are grouped together, such as the insert action that can perform both insert and create. Actions are as granular as MongoDB’s role-based access control gets. The privileges parameter can be used to add roles to mongo actions, and a privilege constitutes the actions along with the resource it applies to. Use the following to add the actions find, insert and update on database “mydb”.

   {resource: {db: "mydb", collection: "" },
   actions: [ “find”,”insert”,”update” ] }

Privilege Resources:

The resource document specifies the scope of which your privilege actions will apply, and can be set at various granularities as follows:

a.  Collection

The resource can be set to resource: {db: "<db-name>", collection: "<collection name>" } to grant the specified actions to only that particular collection.

b. Database

The resource can be set to a particular database by leaving the collection parameter empty. Resource string resource: {db: "<db-name>", collection: "<collection name>" } sets the scope to the entire database.

c. Single Collection Across Databases

The resource can be set to a particular collection using resource: {db: ", collection: "<collection name>" } to grant permissions to the collection on all databases. This permission can only be added onto a role created on the admin database.

d. Multiple Collections Across Databases

The resource can be set to all collections (except the system collections) across all databases by leaving both the db and collection parameters empty. resource: {db: "", collection: "" }. This resource, like the one above, can only be granted on a role created on the admin database.

e. Cluster-Wide Resource

A cluster-wide resource can be specified by using resource: { cluster : true }. This cluster-wide resource is used to specify the state of the system, such as shutdown replSetReconfig rather than granting permissions on any particular document.

f. All Resources

It’s not recommended to use this scope for anything other than extraordinary circumstances. {anyResource: true }  can be used to set scope set to all resource’s.


1.2 Roles:

Inbuilt roles can be added to a custom role as well. When an inbuilt role is added by using the roles: [] parameter, it adds the permissions of the inbuilt role to the custom role.

Here’s an example of the roles parameter:

roles: [{ role: "read", db: "&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;db name&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;"}]

In this example, the custom role would inherit all the permissions of role “read” over the defined database. If a role is inherited onto a database db1, the custom role can either be created on the database db1 or on the admin database.

Write Concern:

Write concern defines the level of acknowledgment requested from MongoDB, and can be used to control write acknowledgments from the database. Note that a write concern is not required when creating a role.  Write concern can include fields w, j and wtimeout:

W – Write Concern

Field W can be used to state the number of instances the write has been propagated to.

J – Write Concern

Field J can be set to determine whether the write is written to the journal.

Wtimeout - Write Concern

This is used to set the time by which the write has to achieve write concern. The write concern might still be achieved after the error is thrown.  If a Wtimeout has not been set and the write concern cannot be achieved, the write will be blocked indefinitely.

2. Assigning Roles:

Custom roles are db specific, and can only be assigned to a user in the same database.

Let’s say we created a role “myrole” on database “db1”. We can create a user on the database using the following commands:

Use db1

db.createUser({"user" : "&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;user&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;",pwd: "&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;password&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;","roles" : [{"role" : "myrole", "db" : "db1"}]})

For further information on user management, refer to this post by Dharshan on user management in MongoDB.

3. Custom Roles:

Let’s go over some custom roles that might be useful.

User role with Read, Insert and Update Permissions on a Single DB:

The inbuilt roles read and readWrite may sometimes feel like too many permissions or too few. Let’s see how we can create a custom role granting just read, insert and write permissions.

We already know we need all read permissions so we can add the inbuilt role “read” to our custom role. We also need permissions to create and update documents, and these can be included by adding privilege actions insert and update. If we wanted to give the user the ability to create index and create collection, we can add the privilege action createIndex and createCollection.

For the scope, let’s assume I have a db named “db1” on which I set the above permissions. The create command would look something like this:

Use db1.



createRole: "&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;role-name&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;",

privileges: [

{ resource: { db: "db1", collection: "" },

actions: [ "insert","update","createIndex", "createCollection" ] }


roles: [{ role: "read", db: "db1"}]


The above command would create a role with <role-name> in database db1.  A user that’s been granted permission by the above role will not have the “remove” privilege action. Also, note that the methods db.collection.findAndModify(),  db.collection.mapReduce() and  db.collection.aggregate() cannot be run in full as they require the remove privilege.

User role with only Read, Insert and Update Permissions on all DB’s:

We can create a role on the admin database that’s similar to the one above, to grant Read, Create and Update privileges on all DB’s. This role should be created on the admin DB and the subsequent user should also be created on the admin DB.

For this role, instead of using the standard read role, we can inherit permissions from readAnyDatabase role. The role create would look something like this:

Use admin.



createRole: "&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;role-name&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;",

privileges: [

{ resource: { db: "", collection: "" },

actions: [ "insert","update","createIndex", "createCollection" ] }


roles: [{ role: "readAnyDatabase", db: "admin"}]


Writer roles with Write Concern

If you have a scenario where write concern needs to be enforced, here’s how it can be added to a role. Adding write concern to a role would enforce it on all of the users granted under this role on the DB. Let’s define a role with a write concern that enforces majority writes:

Use admin.



createRole: "&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;role-name&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;",

privileges: [ ],

roles: [{ role: "readWriteAnyDatabase", db: "admin"}],

writeConcern: { w: “majority”, j: false, wtimeout: 300 }


Liked this post?

Join the ScaleGrid newsletter and never miss out!

Neeraj is a member of technical staff at Scalegrid Inc