# Multi-tenancy <sup style={{ fontSize: '0.6em', color: '#888' }}>Enterprise</sup>

Multi-tenant support in Memgraph enables users to manage multiple isolated
databases within a single instance. The primary objective is to facilitate
efficient resource isolation, maintain data integrity, and manage access for
different clients.

All isolated databases share the underlying CPU resources. Durable storage
is isolated per database — each database has its own data directory under
`databases/`. Per-database RAM usage can be restricted using
[tenant profiles](https://memgraph.com/docs/database-management/tenant-profiles), which enforce a
memory limit on individual databases. Without a tenant profile, global
limitations are imposed on Memgraph as a whole.

## Default (memgraph) database

A default database named `memgraph` is automatically created during startup.
When you create a user or role, they have access to the default database
(memgraph) by default. The default database name cannot be altered.

To remove this default access, you should use `REVOKE DATABASE memgraph FROM role_name;`. Using `REVOKE` removes the default grant but allows the role to potentially receive access through other means (e.g., if combined with another role that has access). Using `DENY` would explicitly forbid access regardless of other roles.

### Default database best practices

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, especially
given recent changes to authentication and authorization requirements.

#### Why treat memgraph as an admin database?

As of Memgraph v3.5, users have to have both the `AUTH` privilege and access to
the default "memgraph" database to execute authentication and authorization
queries. Additionally, replication queries (such as `REGISTER REPLICA`, `SHOW
REPLICAS`, etc.) and multi-database queries (such as `SHOW DATABASES`, `CREATE
DATABASE`, etc.) also now target the "memgraph" database and require access to
it. This requirement affects multi-tenant environments where users might have
access to other databases but not the default one.

#### Recommended setup

1. **Restrict memgraph database access**: Treat the "memgraph" database as a
   system database and allow only administrators to have access to it
2. **Use tenant-specific databases**: Store all application data in dedicated
   tenant databases
3. **Separate concerns**: Keep user management, role management, system
   administration, replication management, and multi-database management
   separate from application data

#### Example configuration

```cypher
-- Create admin role with full system privileges
CREATE ROLE system_admin;
GRANT ALL PRIVILEGES TO system_admin;
GRANT DATABASE memgraph TO system_admin;

-- Create tenant-specific roles (no access to memgraph database)
CREATE ROLE tenant1_admin;
REVOKE DATABASE memgraph FROM tenant1_admin;
CREATE ROLE tenant1_user;
REVOKE DATABASE memgraph FROM tenant1_user;
CREATE ROLE tenant2_admin;
REVOKE DATABASE memgraph FROM tenant2_admin;
CREATE ROLE tenant2_user;
REVOKE DATABASE memgraph FROM tenant2_user;

-- Grant appropriate permissions to tenant roles
GRANT MATCH, CREATE, MERGE, SET, DELETE, INDEX TO tenant1_admin;
GRANT CREATE, READ, UPDATE, DELETE ON NODES CONTAINING LABELS * TO tenant1_admin;
GRANT CREATE, READ, UPDATE, DELETE ON EDGES CONTAINING TYPES * TO tenant1_admin;
GRANT MATCH, CREATE, MERGE, SET, DELETE TO tenant1_user;
GRANT CREATE, READ, UPDATE, DELETE ON NODES CONTAINING LABELS * TO tenant1_user;
GRANT CREATE, READ, UPDATE, DELETE ON EDGES CONTAINING TYPES * TO tenant1_user;
GRANT MATCH, CREATE, MERGE, SET, DELETE, INDEX TO tenant2_admin;
GRANT CREATE, READ, UPDATE, DELETE ON NODES CONTAINING LABELS * TO tenant2_admin;
GRANT CREATE, READ, UPDATE, DELETE ON EDGES CONTAINING TYPES * TO tenant2_admin;
GRANT MATCH, CREATE, MERGE, SET, DELETE TO tenant2_user;
GRANT CREATE, READ, UPDATE, DELETE ON NODES CONTAINING LABELS * TO tenant2_user;
GRANT CREATE, READ, UPDATE, DELETE ON EDGES CONTAINING TYPES * TO tenant2_user;

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

-- Create users
CREATE USER system_admin_user IDENTIFIED BY 'admin_password';
CREATE USER tenant1_admin_user IDENTIFIED BY 't1_admin_pass';
CREATE USER tenant1_regular_user IDENTIFIED BY 't1_user_pass';
CREATE USER tenant2_admin_user IDENTIFIED BY 't2_admin_pass';
CREATE USER tenant2_regular_user IDENTIFIED BY 't2_user_pass';

-- Assign roles
SET ROLE FOR system_admin_user TO system_admin;
SET ROLE FOR tenant1_admin_user TO tenant1_admin;
SET ROLE FOR tenant1_regular_user TO tenant1_user;
SET ROLE FOR tenant2_admin_user TO tenant2_admin;
SET ROLE FOR tenant2_regular_user TO tenant2_user;
```

In this configuration:
- `system_admin_user` can perform all authentication/authorization, replication,
  and multi-database operations and has access to the "memgraph" database
- Tenant users can only access their respective tenant databases
- Application data is completely isolated in tenant-specific databases
- The "memgraph" database serves purely as an administrative database

## Isolated databases

Isolated databases within Memgraph function as distinct single-database Memgraph
instances. Queries executed on a specific database should operate as if it were
the sole database in the system, preventing cross-database contamination. Users
interact with individual databases, and cross-database queries are prohibited.

Every database has its own database UUID, which can be read by running the `SHOW
STORAGE INFO` query on a particular database.

## Database configuration and data directory

At present, all isolated databases share identical configurations. There is no
provision to specify a per-database configuration.

The sole distinction lies in the location of the data directory. The designated
data directory serves as the root and retains data associated with the default
database. Other databases are housed in new directories within
`data_directory/databases/*db_name*`.

The default `memgraph` database also includes a directory
`data_directory/databases/memgraph`, which contains symbolic links leading back
to the root. Some links are proactively generated and their status may vary
based on configuration.

## User interface

### Cypher queries for multi-tenancy

Users interact with multi-tenant features through specialized Cypher queries:

1. `CREATE DATABASE name`: Creates a new database.
2. `DROP DATABASE name [FORCE]`: Deletes a specified database.
3. `RENAME DATABASE old_name TO new_name`: Renames a database.
4. `SHOW DATABASE`: Shows the current used database. It will return `NULL` if no
   database is currently in use. You can also use `SHOW CURRENT DATABASE` for
   the same functionality. This command does not require any special privileges.
5. `SHOW DATABASES`: Shows only the existing set of multitenant databases. The
   result includes a `Name` column, a `State` column (`HOT`/`COLD`) and a
   `Health` column (`ready`/`broken`). `HOT` databases are resident in memory while `COLD` are suspended, but still listed. A database is reported as `broken` when it
   failed durability recovery and came up empty — see
   [recovery failure handling](https://memgraph.com/docs/fundamentals/data-durability#recovery-failure-handling).
6. `USE DATABASE name`: Switches focus to a specific database (disabled during
   transactions).
7. `GRANT DATABASE name TO user_or_role`: Grants a user or role access to a
   specified database.
8. `DENY DATABASE name FROM user_or_role`: Explicitly denies a user or role
   access to a specified database.
9. `REVOKE DATABASE name FROM user_or_role`: Removes the database from the
   user's or role's database access list.
10. `SET MAIN DATABASE name FOR user`: Sets a user's default (landing) database.
11. `SHOW DATABASE PRIVILEGES FOR user`: Lists a user's database access rights.
12. `SUSPEND DATABASE name`: Tears a tenant's in-memory storage down to a durable
    COLD shell to free RAM, keeping its data on disk. See
    [Suspending and resuming databases](#suspending-and-resuming-databases-enterprise).
13. `RESUME DATABASE name`: Rebuilds a suspended (COLD) tenant back to HOT with all
    data intact. See
    [Suspending and resuming databases](#suspending-and-resuming-databases-enterprise).

### Removing database access: DENY vs REVOKE

There are two ways to remove access to a database: `DENY DATABASE x` or `REVOKE
DATABASE x`. They behave differently:

- **DENY** explicitly bans the user or role from the database. If any role that
  a user has (or the user itself) is denied access to a database, the user
  cannot access it. Deny trumps any other access granted—no combination of
  grants can override a deny.
- **REVOKE** removes the database from the user's or role's database access
  list. It does not block access: if the user has other roles (or the user
  itself has access through another path) that still have access to that
  database, the user can still use it when connected to that database
  (tenant).

Use **DENY** when you need to explicitly forbid access to a database for any user with that role, regardless of their other roles. Use **REVOKE** when you simply want to remove the default access (like the default "memgraph" database access) or a previously granted access, allowing the user to potentially access the database if another of their roles grants it.

### DROP DATABASE with FORCE

The `DROP DATABASE` command removes an existing database. You can optionally
include the `FORCE` parameter to delete a database even when it has active
connections or transactions.

#### Syntax
 

```cypher
DROP DATABASE database_name [FORCE];
```

#### Behavior
 

- **Without `FORCE`**: The command will fail if the database is currently in use
  by any active connections or transactions.
- **With `FORCE`**: The database will be immediately hidden from new connections,
  but actual deletion is deferred until it's safe to proceed. All active
  transactions using the database will be terminated.

#### Use cases for FORCE
 

- **Emergency cleanup**: Remove a database stuck in an inconsistent or
  long-running state.
- **Administrative maintenance**: Perform system maintenance requiring immediate
  database removal.
- **Development environments**: Quickly reset test environments that might still
  have active connections.

#### Privileges required
 

Using the `FORCE` option requires:
- `MULTI_DATABASE_EDIT` privilege
- Access to the `memgraph` database
- `TRANSACTION_MANAGEMENT` privilege (to terminate active transactions)

#### Important considerations
 

- All active transactions on the target database will be forcibly terminated.
- The database becomes immediately unavailable to new connections.
- Actual deletion may be deferred until existing connections are properly closed.
- **This operation cannot be undone.**

### RENAME DATABASE

The `RENAME DATABASE` command allows you to rename an existing database to a new
name. This simplifies administrative workflows by eliminating the need to create
a new database, recover from a snapshot, and drop the old database.

#### Syntax
 

```cypher
RENAME DATABASE old_name TO new_name;
```

#### Behavior
 

- The database is **renamed immediately** without requiring unique access.
- If you are currently using the database being renamed, the current database
  context is automatically updated to the new name.
- All existing data, indexes, constraints, and other database objects are
  preserved.

> **Info**
>
> Current implementation of `RENAME` does not update auth data. User/role database
> access and database-specific roles information is not updated. This can lead to
> unindented access to databases.

#### Important considerations
 

- The `RENAME DATABASE` command requires the `MULTI_DATABASE_EDIT` privilege and
  access to the `memgraph` database.
- The new database name must not already exist.
- The old database name must exist.
- This operation cannot be undone once completed.
- All active connections to the database will continue to work seamlessly with
  the new name.

### Suspending and resuming databases <sup style={{ fontSize: '0.6em', color: '#888' }}>Enterprise</sup>

In a multi-tenant instance, every **HOT** tenant keeps its full graph in RAM.
When most tenants are idle at any given moment, this caps how many tenants fit on
a node. Suspending a tenant tears down its in-memory storage — reclaiming that
RAM — while leaving a lightweight, durable **COLD** shell on disk. Resuming
rebuilds the tenant HOT from disk with all data intact.

> **Info**
>
> **Cold is a memory state, not a data state.** Suspending a database never deletes
> or loses data; it only drops the in-memory copy. The on-disk snapshot and WAL are
> left untouched, and resuming recovers the tenant to exactly where it was.

#### Syntax

```cypher
SUSPEND DATABASE database_name;   -- HOT → COLD, frees RAM
RESUME DATABASE database_name;    -- COLD → HOT, rebuilds from disk
```

A successful `SUSPEND DATABASE mydb` returns `Successfully suspended database
mydb`; a successful `RESUME DATABASE mydb` returns `Successfully resumed database
mydb`. Resuming a database that is already HOT is an idempotent success and
returns `Database mydb is already resumed (HOT).`

#### Example

```cypher
-- Free the RAM held by an idle tenant.
SUSPEND DATABASE mydb;

-- Confirm it is now COLD (its data is still on disk).
SHOW DATABASES;
-- Name    state
-- memgraph  HOT
-- mydb      COLD

-- Bring it back into memory before querying it again.
RESUME DATABASE mydb;

-- mydb is HOT again, with all data intact.
USE DATABASE mydb;
MATCH (n) RETURN count(n);
```

#### Privileges required

`SUSPEND DATABASE` and `RESUME DATABASE` require the `MULTI_DATABASE_EDIT`
privilege and access to the `memgraph` database — the same requirements as
`CREATE`/`DROP`/`RENAME DATABASE`. Both are **Enterprise-only**; without a valid
enterprise license the query is rejected with `Access to multi-tenancy requires an
enterprise, ai_platform, or oem license.`

#### Requirements and restrictions

A database can be suspended only when all of the following hold:

- **It is not the default `memgraph` database.** Attempting to suspend it fails
  with `Cannot suspend the default database.`
- **It uses the in-memory transactional storage mode.** On-disk and in-memory
  analytical databases cannot be suspended (analytical mode suppresses the WAL),
  and the query fails with `Database <name> is not in-memory mode; only in-memory
  databases can be suspended.`
- **Periodic snapshots and WAL are enabled** for the database, so a suspended
  tenant is recoverable. Otherwise the query fails with `Database <name> does not
  have periodic snapshot+WAL durability enabled; cannot suspend safely.`
- **No client is using it.** Suspend does not terminate in-flight work; it waits
  briefly for the tenant to become idle and, if connections or transactions are
  still active, returns the retriable `Database <name> has active connections;
  cannot suspend while in use.` Disconnect the clients (or wait for their
  transactions to finish) and re-issue the query.

Suspending a non-existent or already-suspended database returns `Database <name>
does not exist or is already cold.`

If a resume fails to rebuild the storage (for example, under memory pressure), the
tenant is left **COLD** and the query returns `Database <name> failed to recover
while resuming; it remains suspended (cold) and the resume can be retried.` No
data is lost — retry the resume. Resuming a database that is not suspended returns
`Database <name> does not exist or is not suspended.`

#### Working with a suspended database

A COLD database is not queryable until it is resumed. The behavior of other
commands on a suspended tenant is:

- **`USE DATABASE <cold>`** (or the first query on a session pointed at a cold
  tenant) fails with `Database "<name>" is suspended (cold); run RESUME DATABASE
  <name> before using it.` Run `RESUME DATABASE` first, then use it. (Resume is
  not automatic on access.)
- **`SHOW DATABASES`** lists the tenant with its `state` shown as `COLD`.
- **`SHOW STORAGE INFO ON DATABASE <cold>`** succeeds and returns the tenant's
  statistics as of the moment it was suspended (its `state` field reads `COLD`).
  Fields that only exist for a running database — such as `query_memory_tracked`,
  `vector_index_memory_tracked` and `tenant_memory_tracked` — read `0 B`, and
  `tenant_memory_limit` reads `unlimited`. See
  [Server stats](https://memgraph.com/docs/database-management/server-stats#per-database-storage-information).
- **`DROP DATABASE <cold>`** drops the tenant directly, without resuming it; the
  name becomes immediately reusable.
- **`RENAME DATABASE <cold>`** is rejected with `Cannot rename database <old_name>:
  it is suspended (cold). RESUME it first.`
- **Metadata-only commands do not resume the tenant.** `GRANT`/`DENY`/`REVOKE
  DATABASE`, `SET MAIN DATABASE`, `SHOW DATABASES` and tenant-profile operations
  all operate on a cold tenant without bringing it back into memory.

#### Durability and snapshots

`SUSPEND DATABASE` does **not** take a proactive snapshot. Durability at suspend
time is whatever the tenant's periodic snapshot and WAL already provide, plus — if
[`--storage-snapshot-on-exit`](https://memgraph.com/docs/database-management/configuration) is enabled — the
snapshot the storage writes during its normal teardown. Because `RESUME` recovers
from the latest snapshot plus WAL replay, data is intact either way; enabling
`--storage-snapshot-on-exit` mainly makes the subsequent resume faster by reducing
the amount of WAL to replay.

The COLD state is persisted, so **suspended databases survive a restart**: on
recovery a COLD tenant is restored as a durable shell (no RAM is used until you
resume it), and HOT tenants are recovered normally.

#### Replication

`SUSPEND`/`RESUME DATABASE` are system-replicated, exactly like `CREATE`/`DROP
DATABASE`. Issue them on the **MAIN**; each registered replica applies the same
transition and converges to MAIN's authoritative HOT/COLD set — including
replicas that were disconnected, lagging, or restarted while the transition
happened. You do **not** (and cannot) suspend or resume on a replica: these
queries are rejected there with `Query forbidden on the replica!`.

#### Observability

Suspend/resume activity is exported through Prometheus metrics:
`memgraph_database_suspends_total`, `memgraph_database_resumes_total`, the
`memgraph_cold_databases` gauge (current number of suspended databases), and the
`memgraph_database_suspend_latency_seconds` / `memgraph_database_resume_latency_seconds`
histograms. See [Monitoring](https://memgraph.com/docs/database-management/monitoring).

### User's main database

Administrators assign default databases to users, ensuring a seamless and secure
connection experience. Users cannot connect to Memgraph if they lack access
rights to their default database. This situation may arise from database
deletion or revoked access rights.

### User privileges and database access

Authentication and authorization data are shared across databases, providing a
unified source of truth. A single user can access multiple databases with a
global set of privileges, but currently, per-database privileges cannot be
granted.

> **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.

Access to all databases can be granted or revoked using wildcards:
`GRANT DATABASE * TO user;`, `DENY DATABASE * FROM user;` or 
`REVOKE DATABASE * FROM user;`.

### Multi-database queries and the memgraph database

As of Memgraph v3.5 multi-database queries (such as `SHOW DATABASES`, `CREATE
DATABASE`, `DROP DATABASE`, `RENAME DATABASE`, etc.) target the "memgraph"
database and require access to it.

To execute these queries, users must have:
- The appropriate privileges (`MULTI_DATABASE_USE`, `MULTI_DATABASE_EDIT`)
- **AND** access to the default "memgraph" database

### Multi-tenant query syntax changes

As of Memgraph v3.5 the syntax for certain queries in multi-tenant environments
have changed. The `SHOW ROLE` and `SHOW PRIVILEGES` commands now require
specifying the database context in some cases.

**SHOW ROLE FOR USER**: This command does not require database specification and
will show all roles assigned to the user across all databases.

**SHOW PRIVILEGES FOR USER**: This command requires database specification in
multi-tenant environments.

**SHOW PRIVILEGES FOR ROLE**: This command does not require database
specification and will show all privileges for the role.

In multi-tenant environments, you must specify which database context to use
when showing privileges for users:

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;
```

#### SHOW PRIVILEGES syntax in multi-tenant environments

Similarly, the `SHOW PRIVILEGES` command requires database context specification:

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

2. **Show privileges for the current database:**
```cypher
SHOW PRIVILEGES FOR user_or_role ON CURRENT;
```

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

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

#### Impact on multi-tenant environments

In multi-tenant environments where users might not have access to the "memgraph"
database, multi-database management operations will fail. This reinforces the
recommendation to treat the "memgraph" database as an administrative/system
database.

#### Example: Admin user with multi-database privileges

```cypher
-- Create admin role with multi-database privileges
CREATE ROLE multi_db_admin;
GRANT MULTI_DATABASE_USE, MULTI_DATABASE_EDIT TO multi_db_admin;
GRANT DATABASE memgraph TO multi_db_admin;

-- Create user with multi-database admin role
CREATE USER db_admin IDENTIFIED BY 'admin_password';
SET ROLE FOR db_admin TO multi_db_admin;
```

In this setup, `db_admin` can:
- Execute all multi-database queries (`SHOW DATABASES`, `CREATE DATABASE`, `DROP
  DATABASE`, `RENAME DATABASE`, etc.)
- Access the "memgraph" database for administrative operations
- Manage the multi-tenant database configuration

#### Best practice

For multi-database management, ensure that users who need to perform
multi-database operations have both the appropriate multi-database privileges
and access to the "memgraph" database. This aligns with the overall
recommendation to treat the "memgraph" database as an administrative database in
multi-tenant environments.

### Additional multi-tenant privileges

Administrators manage multi-tenant privileges with:

- `MULTI_DATABASE_USE`: Enables database switching and listing.
- `MULTI_DATABASE_EDIT`: Permits database creation and deletion.

### Configuration flags

The `data-recovery-on-startup` flag replaces `storage-recover-on-startup`,
facilitating recovery of individual databases and their contents during startup.
`storage-recover-on-startup` no longer works; see [deprecated
features](https://memgraph.com/docs/database-management/upgrades/deprecated-features) for the versions
that deprecated and removed it.

### Connecting to a database

The user can interact with multi-tenant databases in two ways:

1. Through Cypher queries.
2. When using Neo4j drivers, by defining the `database` field. 
   The `USE DATABASE` query is disabled when the database field is defined. 
   All queries run against the specified database only.

When connecting to Memgraph without defining a particular landing database, 
you will be connected to the default database set for the user. In case the user
does not have a default (main) database, a database-less connection will be 
established. During this connection, the user can execute queries that do not 
manipulate any data. User can still use multi-tenant queries and define a 
database to use via the appropriate Cypher query.

Example using Neo4j Python driver:

```python
import neo4j

driver = neo4j.GraphDatabase.driver("bolt://localhost:7687", auth=("user", "pass"))

with driver.session() as session:
    session.run(...)  # Executes on the default database
    session.run("USE DATABASE db1")
    session.run(...)  # Executes on db1

with driver.session(database="db2") as session:
    session.run(...)  # Executes on db2
    session.run("USE DATABASE db1")  # Error: database switching disabled
```

### Audit Logs

Audit logs now encompass the active database name, positioned immediately after
the username field.

## Backwards compatibility

The multi-tenant feature ensures backwards compatibility, facilitating smooth
version upgrades and downgrades without disrupting user experience. During an
upgrade, previous data is migrated to the default database, while downgrading
retains data solely in the default database.

For detailed upgrade procedures — including high-availability clusters and
rolling upgrades — see the [Upgrades](https://memgraph.com/docs/database-management/upgrades) page and
the [version-specific guides](https://memgraph.com/docs/database-management/upgrades/specific-versions).
