# Role-based access control <sup style={{ fontSize: '0.6em', color: '#888' }}>Enterprise</sup>

**Role-Based access control (RBAC)** simplifies data security by grouping users
into roles based on their tasks. Instead of assigning privileges and permissions
to each user, RBAC assigns privileges and permissions to roles. Users, when
linked to roles, gain the necessary access for their responsibilities. For
example, in a company, a manager's role might have different access levels than
an employee's role.  Through RBAC, organizations efficiently ensure that users
only access data relevant to their role, enhancing security and minimizing
risks.

With role-based access control, a database administrator can assign various
privileges to roles, but for even more control over who can access certain data,
Memgraph Enterprise offers [fine-grained access
control](#fine-grained-access-control). Additionally, you can use [user
profiles](https://memgraph.com/docs/database-management/authentication-and-authorization/user-profiles)
to set resource limits for users.

> **Info**
>
> [Multi-role users and multi-tenant
> roles](https://memgraph.com/docs/database-management/authentication-and-authorization/multiple-roles) for
> more information regarding assigning multiple roles to users or assigning roles
> for a specific database.

## User roles

Users can be assigned multiple roles simultaneously, with permissions from all
roles being combined. User roles are abstractions that capture the privilege
levels of a set of users.

For example, suppose that `Dominik` and `Marko` belong to the upper management
of a certain company. It makes sense to grant them a set of privileges that
other users are not entitled to so, instead of granting those privileges to each
of them, we can create a role with those privileges called `manager`, which we
assign to `Dominik` and `Marko`.

In other words, each privilege that is granted to a user role is automatically
granted to all the users with that role (unless it has been explicitly denied to
that user). Similarly, each privilege that is denied to a user role is
automatically denied to all users with that role (even if it has been explicitly
granted to that user).

When a user has multiple roles, their permissions are combined using the
following rules:
- **Grants**: If any role grants a permission, the user has that permission
- **Denies**: If any role denies a permission, the user is denied that
  permission
- **Database Access**: If any role grants access to a database, the user has
  access
- **Fine-grained Permissions**: Label-based, edge type, and property permissions
are merged using grant/deny logic. See [Fine-grained access control](#fine-grained-access-control)
below for details on how these permissions work and are combined.

> **Info**
>
> Users and roles are in separate namespaces and can share the same name. For
> example, you can have both a user and a role named `admin`. In commands that
> accept either a user or a role (such as `GRANT`, `DENY`, `REVOKE`, and `SHOW
> PRIVILEGES FOR`), use the optional `USER` or `ROLE` keyword to disambiguate
> when the name is shared.

To create a user role, run the following query:

```cypher
CREATE ROLE [IF NOT EXISTS] role_name;
```

If a role already exists, you can use `IF NOT EXISTS` to only create new roles.

To assign roles to a user, you can use either of the following commands:

```cypher
SET ROLE FOR user_name TO role_name [, another_role, ...];
```

```cypher
GRANT ROLE[S] role_name [, another_role, ...] TO user_name;
```

`SET ROLE FOR` replaces all of a user's roles in one operation. `GRANT ROLE[S]`
adds the specified roles to any that the user already has, allowing roles to be
assigned incrementally. Both commands accept an optional `ON database_name`
clause to assign roles for a specific database.

To remove specific roles from a user:

```cypher
REVOKE ROLE[S] role_name [, another_role, ...] FROM user_name;
```

This also accepts an optional `ON database_name` clause.

To remove all roles from the user, run the following query:

```cypher
CLEAR ROLE FOR user_name [ON database_name];
```

To show all users with a certain role:

```cypher
SHOW USERS FOR [ROLE] role_name;
```

To show what roles a user has, run the following query:

```cypher
SHOW ROLE FOR user_name;
```

**Note**: The `SHOW ROLE FOR USER` command does not require database
specification, even in multi-tenant environments. It will show all roles
assigned to the user across all databases.

To show the current user's roles in the current session:

```cypher
SHOW CURRENT ROLE;
```

In multi-tenant environments, you can optionally specify which database context
to use when showing roles:

1. **Show roles for the user's main database:**
```cypher
SHOW ROLE FOR user_name ON MAIN;
```

2. **Show roles for the current database:**
```cypher
SHOW ROLE FOR user_name ON CURRENT;
```

3. **Show roles for a specific database:**
```cypher
SHOW ROLE FOR user_name ON DATABASE database_name;
```

> **Warning**
>
> User-role mappings are simple maps located in the user. Deleting or renaming the database will not update this information. The admin needs to make sure the correct access is maintained at all times.

These commands return the aggregated roles for the user in the specified
database context. The `ON MAIN` option shows roles for the user's main database,
`ON CURRENT` shows roles for whatever database is currently active, and `ON
DATABASE` shows roles for the explicitly specified database.

To list all defined user roles run:

```cypher
SHOW ROLES;
```

This returns each role's name and a `builtin` flag indicating whether it is a
[built-in role](#built-in-roles-enterprise).

To delete a role:

```cypher
DROP ROLE role_name;
```

A role can only be dropped when no users are assigned to it. Remove all user
assignments first.

## Built-in roles <sup style={{ fontSize: '0.6em', color: '#888' }}>Enterprise</sup>

On Memgraph Enterprise, three built-in roles are created automatically when the
first user is created, provided no roles exist yet:

| Role | Privileges | Fine-grained access | Property access | Database access |
|------|-----------|---------------------|-----------------|-----------------|
| `admin` | All privileges | Full read/write on all labels and edge types | `READ`, `SET PROPERTY` on all properties | All databases |
| `readwrite` | `MATCH`, `CREATE`, `MERGE`, `DELETE`, `SET`, `REMOVE`, `INDEX` | Full read/write on all labels and edge types | `READ`, `SET PROPERTY` on all properties | Default `"memgraph"` database only |
| `readonly` | `MATCH`, `STATS` | Read-only on all labels and edge types | `READ` on all properties | Default `"memgraph"` database only |

Built-in roles are created only once and are marked with `builtin: true` in
`SHOW ROLES`. They behave like regular roles and can be assigned to users, but
cannot be deleted while any user is assigned to them. Built-in roles can be
modified like any other role, but doing so removes the `builtin` flag.

The `readwrite` and `readonly` roles only have access to the default
`"memgraph"` database. To grant access to additional databases:

```cypher
GRANT DATABASE database_name TO readwrite;
GRANT DATABASE database_name TO readonly;
```

The first user is assigned the `admin` role automatically, so you do not need
to grant privileges manually for initial setup.

If you choose not to use the built-in roles, you can reproduce the same
configuration manually using the [templates for granting
privileges](#templates-for-granting-privileges).

## User profiles

User profiles allow you to set resource limits for individual users to control
resource consumption and prevent system abuse.

For detailed information about user profiles, including profile creation,
management, and advanced features, see the [User
profiles](https://memgraph.com/docs/database-management/authentication-and-authorization/user-profiles)
documentation.

## Privileges

At the moment, privileges are confined to users' abilities to perform certain
`OpenCypher` queries. Namely, users can be given permission to execute a subset
of the following commands:

| Privilege description | Clause |
| --------------------- | ------ |
| Privilege to [interact with a database](https://memgraph.com/docs/database-management/multi-tenancy). | `DATABASE` |
| Privilege to [access data](https://memgraph.com/docs/querying/read-and-modify-data). | `MATCH` |
| Privilege to [modify data](https://memgraph.com/docs/querying/read-and-modify-data). | `MERGE`, `SET`|
| Privilege to [create](https://memgraph.com/docs/querying/create-graph-objects) and [delete](https://memgraph.com/docs/querying/read-and-modify-data) data. | `CREATE`, `DELETE`, `REMOVE` |
| Privilege to [index data](https://memgraph.com/docs/fundamentals/indexes). | `INDEX` |
| Privilege to [obtain statistics and information](https://memgraph.com/docs/database-management/server-stats) from Memgraph. | `STATS` |
| Privilege to view and alter users, roles and privileges. | `AUTH` |
| Privilege to enforce [constraints](https://memgraph.com/docs/fundamentals/constraints). | `CONSTRAINT` |
| Privilege to [dump the database](https://memgraph.com/docs/configuration/data-durability-and-backup#database-dump).| `DUMP` |
| Privilege to use [replication](https://memgraph.com/docs/clustering/replication) queries. | `REPLICATION` |
| Privilege to access files in queries, for example, when using `LOAD CSV`, `LOAD JSONL` and `LOAD PARQUET` clauses. | `READ_FILE` |
| Privilege to manage [durability files](https://memgraph.com/docs/configuration/data-durability-and-backup#database-dump). | `DURABILITY` |
| Privilege to try and [free memory](https://memgraph.com/docs/fundamentals/storage-memory-usage#deallocating-memory). | `FREE_MEMORY` |
| Privilege to use [trigger queries](https://memgraph.com/docs/fundamentals/triggers). | `TRIGGER` |
| Privilege to [configure Memgraph during runtime](https://memgraph.com/docs/database-management/configuration) and to attain the configuration of the given Memgraph instance. | `CONFIG` |
| Privilege to use [stream queries](https://memgraph.com/docs/data-streams). | `STREAM` |
| Privilege to read the content of Python [query module files](https://memgraph.com/docs/advanced-algorithms). | `MODULE_READ` |
| Privilege to modify the content of Python [query modules files](https://memgraph.com/docs/advanced-algorithms). | `MODULE_WRITE` |
| Privilege to connect to [Memgraph monitoring server](https://memgraph.com/docs/database-management/monitoring). | `WEBSOCKET`
| Privilege to [show and terminate transactions](https://memgraph.com/docs/fundamentals/transactions#terminate-transactions). | `TRANSACTION_MANAGEMENT` |
| Privilege to change [storage mode](https://memgraph.com/docs/fundamentals/storage-memory-usage#storage-modes). | `STORAGE_MODE` |
| Privilege to manage [multi-tenant databases](https://memgraph.com/docs/database-management/multi-tenancy). | `MULTI_DATABASE_EDIT` |
| Privilege to use a database within the multi-tenant architecture. | `MULTI_DATABASE_USE` |
| Privilege to [impersonate other users](https://memgraph.com/docs/database-management/authentication-and-authorization/impersonate-user). | `IMPERSONATE_USER` |
| Privilege to use [parallel execution](https://memgraph.com/docs/querying/parallel-execution). | `PARALLEL_EXECUTION` |
| Privilege to set limits and monitor resource usage per user (via [user profiles](https://memgraph.com/docs/database-management/authentication-and-authorization/user-profiles)) or per database (via [tenant profiles](https://memgraph.com/docs/database-management/tenant-profiles)). | `PROFILE_RESTRICTION` |
| Privilege to manage [server-side parameters](https://memgraph.com/docs/database-management/server-side-parameters) (`SET`, `UNSET`, `SHOW`). | `SERVER_SIDE_PARAMETERS` |
| Privilege to manage [server-side descriptions](https://memgraph.com/docs/database-management/server-side-descriptions) (`SET`, `DELETE`, `SHOW`). | `SERVER_SIDE_DESCRIPTIONS` |
| Privilege to reload [SSL/TLS certificates](https://memgraph.com/docs/database-management/ssl-encryption#reload-ssl-certificates-at-runtime) at runtime (`RELOAD BOLT_SERVER TLS`, `RELOAD INTRA_CLUSTER TLS`). | `RELOAD_TLS` |
| Privileges to specific labels. | `ALL LABELS` |
| Privileges to specific relationships types. | `ALL EDGE TYPES` |

> **Info**
>
> For a comprehensive reference of which privileges are required for specific queries and operations, see the [Query privileges reference](https://memgraph.com/docs/database-management/authentication-and-authorization/query-privileges) documentation.

> **Warning**
>
> **Breaking change in Memgraph 3.13:** the `COORDINATOR` privilege was removed —
> it never gated any operation. It is no longer accepted in `GRANT` / `DENY` /
> `REVOKE` statements and is no longer reported by `SHOW PRIVILEGES`. A stale
> `COORDINATOR` grant in an existing deployment is never reported and never
> checked, so no migration is needed.
>
> Access to [high availability](https://memgraph.com/docs/clustering/high-availability) coordinators is now
> controlled by the `COORDINATOR_READ` and `COORDINATOR_WRITE` privileges. These
> are **coordinator-only**: they are granted to roles that live on the
> coordinators themselves, they are not part of the data-instance privilege set,
> and `GRANT ALL PRIVILEGES` on a data instance does not grant them. See
> [coordinator
> authentication](https://memgraph.com/docs/clustering/high-availability/coordinator-authentication).

### First user privileges

When you create the first user in Memgraph, that user automatically becomes a
superuser with full system access.

On **Memgraph Enterprise**, the first user is automatically assigned the
built-in `admin` role, which grants all privileges, full fine-grained access,
and access to all databases. See [Built-in roles](#built-in-roles-enterprise)
for details. Successively created users beyond the first are not automatically
assigned roles.

On **Memgraph Community**, the first user is granted all privileges directly.
See the [templates for granting privileges](#templates-for-granting-privileges)
section for details on what privileges are granted.

## Authentication and authorization requirements

> **Info**
>
> As of Memgraph v3.5 users can have different privileges on different databases.
> This is due to v3.5 introducing users with multiple roles and database specific
> roles. All system queries (auth, replication and multi-database) now target the
> default "memgraph" database. Meaning that in order to execute one of these
> queries, a user must have the appropriate privilege AND access to "memgraph"
> database. The recommendation is to use the default "memgraph" database as an
> admin/system database and store graphs under other databases.

### System queries in multi-tenant environments

To execute system queries (auth, replication and multi-database), users must have:
- The appropriate privileges (`AUTH`, `REPLICATION`, `MULTI_DATABASE_USE`, `MULTI_DATABASE_EDIT`)
- **AND** access to the default "memgraph" database

### Recommended approach for multi-tenant environments

In multi-tenant environments, we recommend treating the default "memgraph"
database as an administrative/system database rather than storing application
data in it. This approach provides better security and isolation:

1. **Restrict access to the memgraph database**: Only grant access to privileged
   users who need to perform authentication, authorization, replication, or
   multi-database management operations
2. **Use tenant-specific databases**: Store application data in dedicated tenant
   databases rather than the default database
3. **Separate administrative functions**: Keep user management, system
   administration, replication management, and multi-database management
   separate from application data

#### Example setup for multi-tenant environments

```cypher
-- Create tenant-specific roles
CREATE ROLE tenant1_user;
CREATE ROLE tenant2_user;

-- Grant appropriate permissions to tenant roles
GRANT MATCH, CREATE, MERGE, SET, DELETE TO tenant1_user;
GRANT MATCH, CREATE, MERGE, SET, DELETE TO tenant2_user;

-- Grant access to tenant databases only
GRANT DATABASE tenant1_db TO tenant1_user;
GRANT DATABASE tenant2_db TO tenant2_user;

-- Create users
-- On Enterprise, the first user is automatically assigned the built-in admin role
CREATE USER admin_user IDENTIFIED BY 'admin_password';
CREATE USER tenant1_user_account IDENTIFIED BY 'password1';
CREATE USER tenant2_user_account IDENTIFIED BY 'password2';

-- Assign roles to tenant users
SET ROLE FOR tenant1_user_account TO tenant1_user;
SET ROLE FOR tenant2_user_account TO tenant2_user;
```

In this setup:
- `admin_user` is the first user created, so on Enterprise it is automatically
  assigned the built-in `admin` role and has full access to all databases
- `tenant1_user_account` and `tenant2_user_account` can only access their
  respective tenant databases
- Application data is stored in tenant-specific databases, not in the default
  "memgraph" database

After the first user is created, Memgraph switches from "allow everything" mode
(when no users exist) to "access controlled" mode. From that point forward, all
connections must authenticate with valid credentials, and unauthenticated
connections will be rejected.

Memgraph will execute a query if and only if either a user or its role is
granted that privilege and neither the user nor its role are denied that
privilege. Otherwise, Memgraph will not execute that specific query. Note that
`DENY` is a stronger operation than `GRANT`. This is also notable from the fact
that if neither the user nor its role are explicitly granted or denied a certain
privilege, that user will not be able to perform that specific query. This effect
is also known as a silent deny. The information above is neatly condensed in the
following table:

User Status | Role Status | Effective Status
------------|-------------|------------------
GRANT       | GRANT       | GRANT
GRANT       | DENY        | DENY
GRANT       | NULL        | GRANT
DENY        | GRANT       | DENY
DENY        | DENY        | DENY
DENY        | NULL        | DENY
NULL        | GRANT       | GRANT
NULL        | DENY        | DENY
NULL        | NULL        | DENY

Once the privileges are changed, they take full effect once the user reconnects
to the database.

#### Grant privileges

To grant a certain set of privileges to a specific user or user role, use the
following query:

```cypher
GRANT privilege_list TO [USER | ROLE] user_or_role;
```

The optional `USER` or `ROLE` keyword is only needed when a user and a role
share the same name, to disambiguate which one is targeted. The same applies
to `DENY` and `REVOKE`.

For example, to grant `AUTH` and `INDEX` privileges to users with the
`moderator` role, run:

```cypher
GRANT AUTH, INDEX TO moderator;
```
#### Deny privileges

Similarly, denying privileges is done using the `DENY` keyword instead of
`GRANT`.

For example, to deny `AUTH` and `INDEX` privileges to users with the
`moderator` role, run:

```cypher
DENY AUTH, INDEX TO moderator;
```

#### Revoke privileges

Both denied and granted privileges can be revoked, meaning that their status is
not defined for that user or role. Revoking is done using the `REVOKE` keyword.

For example, to revoke `AUTH` and `INDEX` privileges to users with the
`moderator` role, run:

```cypher
REVOKE AUTH, INDEX FROM moderator;
```

Although semantically unintuitive, the level of a certain privilege can be
raised by using `REVOKE`. For instance, if a user has been denied the `INDEX`
privilege, but the role it belongs to is granted that privilege, the user is
unable to use indexing features.

If the user's `INDEX` privilege is revoked, they will be able to use indexing
features because the role is granted that privilege.

#### Manage all privileges at once

To grant, deny or revoke all privileges, use the `ALL PRIVILEGES` construct:

```cypher
GRANT ALL PRIVILEGES TO [USER | ROLE] user_or_role;
```

```cypher
DENY ALL PRIVILEGES TO [USER | ROLE] user_or_role;
```

```cypher
REVOKE ALL PRIVILEGES FROM [USER | ROLE] user_or_role;
```

> **Warning**
>
> The user needs to reconnect to the database for the changes to take effect.

> **Info**
>
> If you get an error: `Vertex not created due to not having
> enough permission!` you probably need to grant the fine-grained access control
> to the user. The [fine-grained access control](#fine-grained-access-control)
> section provides more details.

#### Show privileges

To check privilege for a certain user or role, run the following query:

```cypher
SHOW PRIVILEGES FOR [USER | ROLE] user_or_role;
```

In multi-tenant environments, privileges can differ depending on the target
database. The SHOW PRIVILEGE query can be expanded to show privileges on
specific databases as the following:

1. **Show privileges for the user's main database:**
```cypher
SHOW PRIVILEGES FOR [USER | ROLE] user_or_role ON MAIN;
```

2. **Show privileges for the current database:**
```cypher
SHOW PRIVILEGES FOR [USER | ROLE] user_or_role ON CURRENT;
```

3. **Show privileges for a specific database:**
```cypher
SHOW PRIVILEGES FOR [USER | ROLE] user_or_role ON DATABASE database_name;
```

These commands return the aggregated privileges (including label-based and
property-based permissions) for the user or role in the specified database
context.

**Note**:
- For **users**: In multi-tenant environments, you must specify the database
  context.
- For **roles**: This command does not require database specification, even in
  multi-tenant environments. In which case, it will show the role's privileges
  without filtering for database.

## Fine-grained access control

Sometimes, authorizing the database by granting and denying clause privileges is
not enough to make the database fully secure. Certain nodes and relationships
can be confidential and must be restricted from viewing and manipulating by
multiple users. Also, disabling users from executing certain commands is
sometimes too restrictive.

In response to the need for such authorization, Memgraph offers two levels of
fine-grained access control:

- [Label-based access control](#label-based-access-control) (LBAC) enables
authorization on node labels and relationship edge types, controlling which
nodes and relationships a user can see and manipulate.
- [Property-based access control](#property-based-access-control) (PBAC)
enables authorization on individual properties, controlling which properties
a user can read or write on visible nodes and relationships.

By applying authorization to the graph's first-class citizens, a database
administrator can keep all the data in one database while keeping any private
data secure from those who don't have adequate permission.

### Label-based access control

Label-based permissions use `GRANT`, `DENY`, and `REVOKE` to control access.
`DENY` takes precedence over `GRANT`: an explicit deny cannot be overridden by
any grant, regardless of role configuration. If no rule matches a node or edge,
access is denied by default: this is called a "silent deny".

The available permissions are:

| Permission | Applies to | Description |
| ---------- | ---------- | ----------- |
| `CREATE` | nodes | Permission to create a new node with this label, or to add this label to an existing node (requires `SET LABEL` on the node's existing labels) |
| `CREATE` | edges | Permission to create an edge of this type |
| `READ` | nodes, edges | Permission to match nodes or traverse edges |
| `UPDATE` | nodes | Shorthand for `SET LABEL, REMOVE LABEL, SET PROPERTY, CREATE EDGE, DELETE EDGE` |
| `UPDATE` | edges | Shorthand for `SET PROPERTY` |
| `DELETE` | nodes, edges | Permission to delete a node or edge, or to remove a label from a node |
| `SET LABEL` | nodes | Gatekeeper permission: required on a node's existing labels before any label can be added to it |
| `REMOVE LABEL` | nodes | Gatekeeper permission: required on a node's existing labels before any label can be removed from it |
| `SET PROPERTY` | nodes, edges | Permission to set, update, or remove a property on a node or edge |
| `CREATE EDGE` | nodes | Gatekeeper permission: required on a node's labels before an edge can be created incident to it |
| `DELETE EDGE` | nodes | Gatekeeper permission: required on a node's labels before an edge incident to it can be deleted |
| `*` | nodes, edges | All permissions for the entity type |

> **Warning**
>
> **Breaking changes**:
>
> **v3.10.0**: `GRANT NOTHING` and `REVOKE NOTHING` have been removed. Use `DENY`
> instead. For nodes, the `UPDATE` permission on nodes has been expanded into five
> discrete sub-permissions: `SET LABEL`, `REMOVE LABEL`, `SET PROPERTY`, `CREATE
> EDGE`, and `DELETE EDGE`. `UPDATE` remains valid as a shorthand that expands to
> all five. For edges, `UPDATE` is an alias for `SET PROPERTY`.
>
> **v3.7.0**: Label-based permissions changed from a fixed hierarchical model to
> discrete permissions. The `CREATE_DELETE` permission was split into separate
> `CREATE` and `DELETE` permissions. Fine-grained access control rules are now
> set on sets of labels, applying to nodes either `MATCHING ANY` of the given
> labels, or `MATCHING EXACTLY` the rule's label specification.
>
> See the [migration guide](https://memgraph.com/docs/database-management/authentication-and-authorization/mlbac-migration-guide) for details.

#### Node permissions

Granting a certain set of node permissions can be done similarly to the clause
privileges using the following command:

```cypher
GRANT permission ON NODES CONTAINING LABELS label_list [MATCHING ANY| MATCHING EXACTLY] TO user_or_role;
```

with the legend:
- `permission` is a comma-separated list containing one or more of: `CREATE`,
  `READ`, `UPDATE`, `DELETE`, `SET LABEL`, `REMOVE LABEL`, `SET PROPERTY`,
  `CREATE EDGE`, `DELETE EDGE`, or `*` for all permissions
- `label_list` is a set of node labels, separated with a comma and with a colon
in front of each label (e.g. `:Person`), or `*` for a global rule matching all
labels in the graph
- `user_or_role` is the already created user or role in Memgraph
- `MATCHING ANY` means that the rule will apply to any node having one or more
of the specified labels, regardless of any additional labels that the node may
have
- `MATCHING EXACTLY` will mean that the rule will apply to any node having
all of the labels specified, and no additional labels
- If the `MATCHING` clause is omitted, `MATCHING ANY` is assumed by default
- `MATCHING` clauses cannot be used when creating global (`*`) rules

For example, granting a `READ` permission on any nodes with labels `User` or
`Product` to user `charlie` would be written as:

```cypher
GRANT READ ON NODES CONTAINING LABELS :User, :Product MATCHING ANY TO charlie;
```

Note that the `MATCHING ANY` clause may be omitted because this is the default
for labels. The following statement behaves identically to the previous example:

```cypher
GRANT READ ON NODES CONTAINING LABELS :User, :Product TO charlie;
```

Multiple permissions can be granted using multiple statements, building up the
allowed permissions piece-by-piece:

```cypher
GRANT CREATE ON NODES CONTAINING LABELS :Item TO charlie;
GRANT READ ON NODES CONTAINING LABELS :Item TO charlie;
GRANT UPDATE ON NODES CONTAINING LABELS :Item TO charlie;
```

Or they can be granted in a single statement using a comma-separated permission
list:

```cypher
GRANT CREATE, READ, UPDATE ON NODES CONTAINING LABELS :Item TO charlie;
```

Global permissions for all labels can be granted using `*` instead of a list of
labels:

```cypher
GRANT READ ON NODES CONTAINING LABELS * TO charlie;
```

To explicitly deny access to a node, use `DENY`. A deny rule overrides any
grants for the same label specification, regardless of role configuration.

```cypher
DENY * ON NODES CONTAINING LABELS :User, :Person TO charlie;
```

Individual permissions can also be denied:

```cypher
DENY DELETE ON NODES CONTAINING LABELS :ReadOnly TO charlie;
```

`DENY` supports the same `MATCHING ANY` / `MATCHING EXACTLY` clauses as `GRANT`.

Permissions can be revoked using the following syntax:

```cypher
REVOKE permission ON NODES CONTAINING LABELS label_list [MATCHING ANY| MATCHING EXACTLY] FROM user_or_role;
```

The rules for specifying `REVOKE` label specifications are identical to those
when using `GRANT`.

Note that revoking permissions is not the same as denying them. `REVOKE` removes
existing grants or denies for the label specification; `DENY` sets an explicit
deny rule. This distinction matters when it comes to
[merging permissions](#merging-permissions) and
[combining matching rules](#combining-matching-rules).

#### Relationship permissions

Edge type permissions work similarly to node permissions. The available
permissions are `CREATE`, `READ`, `UPDATE` (equivalent to `SET PROPERTY`),
`DELETE`, `SET PROPERTY`, and `*`.

Permissions can be granted using the following syntax:

```cypher
GRANT permission ON EDGES OF TYPE edge_type_list TO user_or_role;
```

where:
- `permission` is a comma-separated list containing one or more of: `CREATE`,
  `READ`, `UPDATE`, `DELETE`, `SET PROPERTY`, or `*` for all permissions
- `edge_type_list` is a set of edge types, separated with a comma and with a
colon in front of each type (e.g. `:KNOWS, :FOLLOWS`), or `*` for all edge types
- `user_or_role` is the already created user or role in Memgraph

Note that edge type permissions do not support `MATCHING` clauses: edges can
only have a single type, so matching modes are not applicable.

For example, granting `READ` permission on edge type `:CONNECTS` to user
`charlie`:

```cypher
GRANT READ ON EDGES OF TYPE :CONNECTS TO charlie;
```

Granting multiple permissions on multiple edge types:

```cypher
GRANT CREATE, READ, UPDATE ON EDGES OF TYPE :KNOWS, :FOLLOWS TO charlie;
```

Global permissions for all edge types:

```cypher
GRANT READ ON EDGES OF TYPE * TO charlie;
```

To deny access to an edge type:

```cypher
DENY permission ON EDGES OF TYPE edge_type_list TO user_or_role;
```

For example:

```cypher
DENY * ON EDGES OF TYPE :CONFIDENTIAL TO charlie;
```

Revoking edge type permissions uses similar syntax:

```cypher
REVOKE permission ON EDGES OF TYPE edge_type_list FROM user_or_role;
```

For example:

```cypher
REVOKE CREATE ON EDGES OF TYPE :KNOWS FROM charlie;
```

As with node permissions, revoking permissions is not the same as denying them.
`REVOKE` removes existing grants or denies; `DENY` sets an explicit deny rule.

#### Permission requirements per operation

The table below shows the minimum permissions required for each operation.
"Label" refers to permissions on the node label(s) involved; "Edge type" refers
to permissions on the relationship type.

| Operation | Label permissions | Edge type permissions |
| --------- | ----------------- | --------------------- |
| `CREATE (:Label)` | `CREATE` on `:Label` | — |
| `MATCH (n:Label) RETURN n` | `READ` on `:Label` | — |
| `MATCH (n:Label) SET n.prop = 1` | `READ`, `SET PROPERTY` on `:Label` | — |
| `MATCH (n:Label) REMOVE n.prop` | `READ`, `SET PROPERTY` on `:Label` | — |
| `MATCH (n:Label) DELETE n` | `READ`, `DELETE` on `:Label` | — |
| `MATCH (n:Label) SET n:NewLabel` | `READ`, `SET LABEL` on `:Label` (existing); `CREATE` on `:NewLabel` (being added) | — |
| `MATCH (n:Label) REMOVE n:OtherLabel` | `READ`, `REMOVE LABEL` on `:Label` (existing); `DELETE` on `:OtherLabel` (being removed) | — |
| `MATCH (a:A), (b:B) CREATE (a)-[:Type]->(b)` | `READ`, `CREATE EDGE` on `:A` and `:B` | `CREATE` on `:Type` |
| `MATCH ()-[r:Type]->() RETURN r` | `READ` on endpoint labels | `READ` on `:Type` |
| `MATCH ()-[r:Type]->() SET r.prop = 1` | `READ` on endpoint labels | `READ`, `SET PROPERTY` on `:Type` |
| `MATCH ()-[r:Type]->() DELETE r` | `READ`, `DELETE EDGE` on endpoint labels | `READ`, `DELETE` on `:Type` |

#### Merging permissions

When a user has multiple roles, or when a user has both role-based and
user-specific permissions, individual permission bits are combined using OR
logic for grants and explicit denies:

- If any role or the user grants a specific permission on a label specification,
the user has that permission
- If any role or the user denies a permission on a label specification, the user
is denied that access, overriding any grants
- Each label specification is evaluated independently based on its label list
and matching mode

For example, if a user has Role A granting `READ` on `:Item` and Role B granting
`UPDATE` on `:Item`, the user will have both `READ` and `UPDATE` permissions on
`:Item` nodes. However, if Role C denies `*` on `:Item`, the explicit deny
overrides all grants, and the user will have no access to any `:Item` nodes.

#### Combining matching rules

When a node matches multiple label specifications, all matching rules are
applied and their permissions are combined:

- The effective permissions for a node are the union (OR) of all grants from
matching rules
- If any matching rule has a deny, it overrides all grants for the affected
permissions
- Rules are matched based on their label specification and matching mode

For example, given the following rules:

```cypher
GRANT READ ON NODES CONTAINING LABELS :User MATCHING ANY TO charlie;
GRANT UPDATE ON NODES CONTAINING LABELS :Employee MATCHING ANY TO charlie;
```

A node with labels `:User:Employee` matches both rules. `charlie` will have both
`READ` and `UPDATE` permissions on this node, since permissions from all
matching rules are combined.

However, if we add an explicit deny:

```cypher
DENY * ON NODES CONTAINING LABELS :Admin MATCHING ANY TO charlie;
```

A node with labels `:User:Employee:Admin` matches all three rules. `charlie`
will be denied all access to this node, since the deny takes precedence over
any grants.

The `MATCHING` mode also affects which rules apply:

```cypher
GRANT READ ON NODES CONTAINING LABELS :User, :Employee MATCHING EXACTLY TO charlie;
GRANT UPDATE ON NODES CONTAINING LABELS :Employee MATCHING ANY TO charlie;
```

- A node with labels `:User:Employee` (only these two labels) matches the first
rule exactly, and the second rule (has `:Employee`). `charlie` has both `READ`
and `UPDATE`
- A node with labels `:User:Employee:Admin` matches only the second
rule (has `:Employee`, but not exactly `:User:Employee`). `charlie` has only
`UPDATE`
- A node with label `:Employee` matches only the second rule. `charlie` has
only `UPDATE`

##### Global permissions and label-specific rules

Global permissions (granted on `*`) act as a fallback when no specific label
specification matches a node. When a node matches a specific label rule,
that rule takes precedence over the global permission.

For example:

```cypher
GRANT READ, UPDATE ON NODES CONTAINING LABELS * TO charlie;
DENY * ON NODES CONTAINING LABELS :Confidential MATCHING ANY TO charlie;
```

- A node with label `:User` has no specific rule match, so the global `*`
permission applies. `charlie` has `READ` and `UPDATE`
- A node with label `:Confidential` matches the specific rule. The deny
overrides the global permission, so `charlie` has no access

Another example:

```cypher
GRANT READ ON NODES CONTAINING LABELS * TO charlie;
GRANT UPDATE ON NODES CONTAINING LABELS :Document MATCHING ANY TO charlie;
```

- A node with label `:User` matches only the global rule. `charlie` has
`READ`
- A node with label `:Document` matches the specific rule. `charlie` has
`UPDATE` from the specific rule, but the global `READ` is replaced by the
specific rule, so `charlie` has only `UPDATE`
- A node with labels `:Document:Draft` matches the specific rule (has
`:Document`). `charlie` has only `UPDATE`

Key principle: Once any specific label rule matches a node, the global `*`
permission is not considered for that node.

#### Show privileges for label-based access control

To check which privileges an existing user or role has in Memgraph, it is enough
to write

```cypher
SHOW PRIVILEGES FOR [USER | ROLE] user_or_role;
```

In multi-tenant environments, privileges can differ depending on the target
database. The SHOW PRIVILEGE query can be expanded to show privileges on
specific databases as the following:

1. **Show privileges for the user's main database:**
```cypher
SHOW PRIVILEGES FOR [USER | ROLE] user_or_role ON MAIN;
```

2. **Show privileges for the current database:**
```cypher
SHOW PRIVILEGES FOR [USER | ROLE] user_or_role ON CURRENT;
```

3. **Show privileges for a specific database:**
```cypher
SHOW PRIVILEGES FOR [USER | ROLE] user_or_role ON DATABASE database_name;
```

These commands return the aggregated privileges (including label-based and
property-based permissions) for the user or role in the specified database
context.

**Note**:
- For **users**: In multi-tenant environments, you must specify the database
  context.
- For **roles**: This command does not require database specification, even in
  multi-tenant environments. In which case, it will show the role's privileges
  without filtering for database.

### Property-based access control

Property-based access control (PBAC) adds a second layer of fine-grained
authorization on top of [label-based access control](#label-based-access-control).
While LBAC controls which nodes and relationships a user can see and manipulate,
PBAC controls which individual properties on those nodes and relationships a user
can read or write.

PBAC uses the same `GRANT`, `DENY`, and `REVOKE` commands as LBAC, with the
same precedence rules: `DENY` overrides `GRANT`, and if no rule matches a
property, access is denied by default (silent deny).

The available permissions are:

| Permission | Description |
| ---------- | ----------- |
| `READ` | Permission to see the value of a property in query results |
| `SET PROPERTY` | Permission to create, update, or remove a property value |

Both permissions apply to properties on nodes and on relationships.

> **Info**
>
> When upgrading from Memgraph v3.11 or earlier, existing users and roles are
> automatically migrated with global access to all properties (`READ` and `SET
> PROPERTY` on `{*}`). This means existing deployments will continue to work
> without any changes after the upgrade.

#### Node property permissions

Property permissions on nodes are granted using the following syntax:

```cypher
GRANT permission_list {property_list} ON NODES CONTAINING LABELS label_list [MATCHING ANY | MATCHING EXACTLY] TO user_or_role;
```

where:
- `permission_list` is a comma-separated list containing `READ`, `SET PROPERTY`,
or both
- `property_list` is either a comma-separated list of property names inside
curly braces (e.g. `{name, email}`), or `{*}` as a wildcard for all properties
- `label_list`, `MATCHING` clauses, and `user_or_role` follow the same rules as
[label-based node permissions](#node-permissions)

For example, granting `READ` permission on the `name` and `email` properties of
`:Employee` nodes to user `charlie`:

```cypher
GRANT READ {name, email} ON NODES CONTAINING LABELS :Employee TO charlie;
```

Multiple permissions can be granted in a single statement:

```cypher
GRANT READ, SET PROPERTY {name, email} ON NODES CONTAINING LABELS :Employee TO charlie;
```

Global property permissions for all labels use `*` in place of the label list:

```cypher
GRANT READ {*} ON NODES CONTAINING LABELS * TO charlie;
```

To deny read access to a specific property:

```cypher
DENY READ {ssn} ON NODES CONTAINING LABELS :Employee TO charlie;
```

`DENY` supports the same `MATCHING ANY` / `MATCHING EXACTLY` clauses as `GRANT`.

To revoke property permissions:

```cypher
REVOKE READ {ssn} ON NODES CONTAINING LABELS :Employee FROM charlie;
```

As with label-based permissions, revoking is not the same as denying. `REVOKE`
removes existing grants or denies for the property specification; `DENY` sets an
explicit deny rule.

#### Relationship property permissions

Property permissions on relationships follow a similar syntax:

```cypher
GRANT permission_list {property_list} ON EDGES OF TYPE edge_type TO user_or_role;
```

where:
- `permission_list` is a comma-separated list containing `READ`, `SET PROPERTY`,
or both
- `property_list` is either a comma-separated list of property names inside
curly braces, or `{*}` as a wildcard for all properties
- `edge_type` is a single edge type (e.g. `:WORKS_AT`) or `*` as a wildcard
for all edge types
- `user_or_role` follows the same rules as
[label-based relationship permissions](#relationship-permissions)

For example, granting `READ` on the `start_date` property of `:WORKS_AT`
relationships:

```cypher
GRANT READ {start_date} ON EDGES OF TYPE :WORKS_AT TO charlie;
```

Denying write access to a property on all edge types:

```cypher
DENY SET PROPERTY {secret_code} ON EDGES OF TYPE * TO charlie;
```

Revoking property permissions on relationships:

```cypher
REVOKE READ {start_date} ON EDGES OF TYPE :WORKS_AT FROM charlie;
```

#### How denied properties behave

When a user does not have `READ` permission on a property, the property value is
hidden from query results. The exact behavior depends on the context:

| Context | Behavior |
| ------- | -------- |
| Direct property access (`n.prop`) | Returns `NULL` |
| `WHERE` clause filtering (`WHERE n.prop = value`) | Property evaluates to `NULL`, so the condition is not satisfied and the node is not returned |
| `properties(n)` | Key is present in the returned map, but its value is `NULL` |
| `keys(n)` | Key is omitted from the returned list |
| `values(n)` | Value is omitted from the returned list |
| `DUMP DATABASE` | Property is omitted from generated `CREATE` statements |
| `SHOW SCHEMA INFO` | Property is omitted from the schema listing |

When a user does not have `SET PROPERTY` permission on a property, any attempt
to write that property (via `SET`, `REMOVE`, `CREATE`, or `MERGE`) will fail
with an error and the transaction will be rolled back.

#### Merging property permissions

Property permissions follow the same merging rules as label-based permissions.
When a user has multiple roles, or both role-based and user-specific property
permissions, the permissions are combined:

- If any role or the user grants a property permission, the user has that
permission
- If any role or the user denies a property permission, the user is denied
that access, overriding any grants

For example, if a user has Role A granting `READ {salary}` on `:Employee` and
Role B denying `READ {salary}` on `:Employee`, the deny takes precedence and the
user cannot see the `salary` property.

Global property permissions (granted on `{*}`) act as a per-property fallback.
For each property access check, the resolution order is:

1. Check all entity-specific rules that match the node's labels (or the edge's
type). If any matching rule covers the property being checked (either by name
or via `{*}` within that rule), use that result.
2. If no matching rule covers the property, fall through to the global rules.

This means that having a property rule on `:Employee` for one property (e.g.
`ssn`) does not affect the resolution of other properties (e.g. `salary`) on
the same label - those still fall through to global rules independently.

#### Example: combining global and per-label rules

Given the following grants for user `auditor`:

```cypher
GRANT READ {*} ON NODES CONTAINING LABELS * TO auditor;
DENY READ {salary} ON NODES CONTAINING LABELS :Employee TO auditor;
```

When `auditor` queries an `(:Employee {name: 'Alice', ssn: '1234', salary: 9999})`
node:

| Property | Resolution | Result |
| -------- | ---------- | ------ |
| `name` | No `:Employee` rule covers `name` → falls through to global `{*}` → **GRANT** | `'Alice'` |
| `ssn` | No `:Employee` rule covers `ssn` → falls through to global `{*}` → **GRANT** | `'1234'` |
| `salary` | `:Employee` rule explicitly denies `salary` → **DENY** | `NULL` |

### Templates for granting privileges

> **Info**
>
> On Memgraph Enterprise, the `admin`, `readwrite`, and `readonly` roles are
> created automatically and match these templates. See [Built-in
> roles](#built-in-roles-enterprise) for details. Use the templates below to
> restore the default roles if you have removed or customized them.

To grant all privileges to a superuser (admin):

```cypher
GRANT ALL PRIVILEGES TO admin;
GRANT DATABASE * to admin;
GRANT CREATE, READ, UPDATE, DELETE ON NODES CONTAINING LABELS * TO admin;
GRANT CREATE, READ, UPDATE, DELETE ON EDGES OF TYPE * TO admin;
GRANT READ, SET PROPERTY {*} ON NODES CONTAINING LABELS * TO admin;
GRANT READ, SET PROPERTY {*} ON EDGES OF TYPE * TO admin;
```

To grant all read and write privileges:

```cypher
DENY ALL PRIVILEGES TO readWrite;
GRANT CREATE, DELETE, MERGE, SET, REMOVE, INDEX, MATCH, STATS TO readWrite;
GRANT CREATE, READ, UPDATE, DELETE ON NODES CONTAINING LABELS * TO readWrite;
GRANT CREATE, READ, UPDATE, DELETE ON EDGES OF TYPE * TO readWrite;
GRANT READ, SET PROPERTY {*} ON NODES CONTAINING LABELS * TO readWrite;
GRANT READ, SET PROPERTY {*} ON EDGES OF TYPE * TO readWrite;
```

To grant read only privileges:

```cypher
DENY ALL PRIVILEGES TO readonly;
GRANT MATCH, STATS TO readonly;
GRANT READ ON NODES CONTAINING LABELS * TO readonly;
GRANT READ ON EDGES OF TYPE * TO readonly;
GRANT READ {*} ON NODES CONTAINING LABELS * TO readonly;
GRANT READ {*} ON EDGES OF TYPE * TO readonly;
```

### Examples

Below are several examples of using the Enterprise security features.

#### Grant read permissions

Bob is a data analyst for the company. He is making sure he can extract any
useful insights from the data imported into the database. For now, all the data
is labeled with the `DataPoint` label. Alice has already created a data analyst
role as well as Bob's account in Memgraph with:

```cypher
CREATE ROLE analyst;
CREATE USER Bob IDENTIFIED BY 'test';
SET ROLE FOR Bob TO analyst;
GRANT DATABASE exampledb TO Bob;
```

Unfortunately, when he writes:

```cypher
MATCH (n:DataPoint) RETURN n;
```

he gets an error that he can not execute the query. Why is that? The first
problem that we encounter is that Bob can not perform `MATCH` queries, which we
must explicitly grant.

The database administrator grants him and all the data analysts the `MATCH`
query to traverse the graph with:

```cypher
GRANT MATCH TO analyst;
```

Now Bob is able to perform a match. However, by executing the same query again,
he is not able to get any results.

Since Bob is not an administrator, he was not able to see any data points in the
graph. In other words, he does not have `READ` permission on the `DataPoint`
label.

Alice now updates Bob's permissions by executing:

```cypher
GRANT READ ON NODES CONTAINING LABELS :DataPoint TO analyst;
```

Bob is now executing his queries normally and is able to get insights from the
database with respect to all the data points in the graph!

Additionally, in the company, it was decided that all the data points would be
connected in a time series fashion, depending on when they were ingested into
the database. One `DataPoint` should therefore be connected to the previously
inserted one. The relationship type is called `:NEXT`.

Bob now again has problems, because when he executes:

```cypher
MATCH (n:DataPoint)-[e:NEXT]->(m:DataPoint);
```

he is not able to see the patterns. Although Bob can see all the data points, he
doesn't have permission to view the relationships. The database administrator
executes the following command to solve the problem:

```cypher
GRANT READ ON EDGES OF TYPE :NEXT TO analyst;
```

Since the users are initially constructed without any permission, they would
need an explicit grant for every new label that appears in the database. This
approach is called whitelisting, and is more secure for adding new entities in
the database since confidential nodes and relationships are not leaked into the
database before securing them.

#### Grant update permissions

Charlie is a tester and customer care specialist. He is in charge of reporting
bugs and fixing issues in the database. A common problem that he is facing is
updating the classes of the data points if they are labeled incorrectly. For
example, the class of one `DataPoint` might be 'dog', while in fact it is an
'elephant', but it was wrongly selected in the rush of labeling many data
points. Charlie needs to update the wrongly labeled data points, and he already
has the IDs of all the nodes he must update.

The administrator has already set up his account with the following commands:

```cypher
CREATE ROLE tester;
CREATE USER Charlie IDENTIFIED BY 'test';
SET ROLE FOR Charlie TO tester;
GRANT DATABASE exampledb TO Charlie;

GRANT MATCH, SET TO tester;

GRANT READ ON NODES CONTAINING LABELS :DataPoint TO tester;
GRANT READ ON EDGES OF TYPE :NEXT TO tester;
```

He now has read privileges just like all the data analysts, but when he gets an
authorization error while executing:

```cypher
MATCH (n:DataPoint {id:505}) SET n.labelY = 'elephant';
```

The error occurs because Charlie does not have permission to update the existing
nodes in the graph. The database administrator needs to update Charlie's
permissions and grant him access to update the node properties with:

```cypher
GRANT UPDATE ON NODES CONTAINING LABELS :DataPoint TO tester;
```

Charlie is now able to update the labeled categories of any data point in the
graph! The same permission applies if he needs to update a relationship property
in the graph.

#### Grant full access permissions

David is the data engineer for the company. He is very skilled in database
systems, and he has been assigned the task of deleting every data point in the
system that's older than one year. Alice has his account set up with the
following commands:

```cypher
CREATE ROLE dataEngineer;
CREATE USER David IDENTIFIED BY 'test';
SET ROLE FOR David TO dataEngineer;
GRANT DATABASE exampledb TO David;

GRANT MATCH, DELETE TO dataEngineer;

GRANT UPDATE ON NODES CONTAINING LABELS :DataPoint TO dataEngineer;
GRANT UPDATE ON EDGES OF TYPE :NEXT TO dataEngineer;
```

However, `UPDATE` privilege capabilities only grant manipulation of properties,
not the nodes and relationships themselves. Therefore, the query:

```cypher
MATCH (n:DataPoint) WHERE localDateTime() - n.date > Duration({day:365}) DETACH DELETE n;
```

results in an error. To delete nodes and relationships, David needs both
`CREATE` and `DELETE` permissions (as well as `READ` to query them). By
executing the following commands:

```cypher
GRANT CREATE, READ, DELETE ON NODES CONTAINING LABELS :DataPoint TO dataEngineer;
GRANT CREATE, READ, DELETE ON EDGES OF TYPE :NEXT TO dataEngineer;
```

The permission is executed on relationships as well, since David needs to detach
the nodes prior to deleting them. David is now able to successfully delete the
deprecated nodes.

#### Deny visibility

Eve is the new senior engineer, and she is making excellent progress in the
company. The management therefore decided to grant her visibility and
manipulation over all the nodes. However, there are certain confidential nodes
that are only for the management people to see.

Since there could be a lot of different node labels or relationship types in the
database, `DENY *` is a convenient shortcut to block all access to a specific
label. The database administrator therefore sets Eve's role as:

```cypher
CREATE ROLE seniorEngineer;
CREATE USER Eve IDENTIFIED BY 'test';
SET ROLE FOR Eve TO seniorEngineer;
GRANT DATABASE exampledb TO Eve;

GRANT MATCH, DELETE TO seniorEngineer;

GRANT CREATE, READ, UPDATE, DELETE ON NODES CONTAINING LABELS * TO seniorEngineer;
DENY * ON NODES CONTAINING LABELS :SecretLabel TO seniorEngineer;
```

The `DENY *` rule denies Eve all access to `:SecretLabel` nodes, overriding the
global grant. Eve can see all domain data while confidential nodes remain
protected.
