# Limit each customer to its own data

> Tenancy is how a data source keeps each customer's data separate, with row-level security, a dataset or database per customer, or none.

Updated: 2026-11-09

Tenancy lets one data source serve all your customers, each with only its own data. In the console at `app.bonnard.ai`,
an Editor or higher sets it on the data source's Tenancy tab.

For each customer's question:

1. Bonnard reads the customer's tenant, the value that marks its data in your database, from its Tenant ID.
2. Your row-level security policies filter the rows to that tenant, or the query reads only its dataset or database.
3. A customer with no tenant gets no data.

[Image: The Tenancy tab: a Tenancy type card reading No tenancy, with None selected and Row-level security beside it]

## Row-level security

Row-level security keeps all customers in shared tables. Before each query, Bonnard puts the tenant in a setting that
your policies read.

Table: The setting that your policies read

| Database | Setting |
| --- | --- |
| PostgreSQL, Amazon Redshift | `current_setting('app.tenant_id')` |
| Microsoft SQL Server | `SESSION_CONTEXT(N'tenant_id')` |

**See setup SQL** on the Tenancy tab gives the PostgreSQL and SQL Server statements to run in your database.

To add customers from a column, set **Tenant ID column (optional)**, then select **Find Tenant IDs**.

## Isolation check

With row-level security, the Tenancy tab examines Bonnard's read-only user and, except on Amazon Redshift, your tables.
After a fix, select **Re-check**.

Bonnard refuses customers when:

- The user is a superuser or has `BYPASSRLS`.
- A PostgreSQL user owns a table without forced row-level security.
- A SQL Server login is in `sysadmin` or `db_owner`, or has `ALTER ANY SECURITY POLICY`.
- A SQL Server policy reads a key other than `tenant_id`.
- The check cannot run.

> [!WARNING]
> Add row-level security to each table with customer data. Without it, all customers read all its rows, and the check
> only warns.

A PostgreSQL table with row-level security and no policy returns no rows.

## Dataset per customer on BigQuery

Each customer has its own BigQuery dataset and service account. Grant each account only its own dataset. On the Tenancy
tab, select an **Example dataset**, then **Follow a pattern** with `{tenant_id}` or **Set each customer**. Set
service accounts, and datasets with no pattern, on the
[Access tab](https://bonnard.ai/docs/access/give-access.md#one-service-account-for-each-customer-on-bigquery). A customer without both gets no data.

## Database per customer on Azure SQL Database

Each customer has its own database. On the Tenancy tab, enter a **Reference database**, then select **Follow a pattern**,
for example `customer_{tenant_id}`, or **Set each customer** to set them on the
[Access tab](https://bonnard.ai/docs/access/give-access.md#access-on-a-data-source-with-tenancy).

## No tenancy

A data source starts on None, where everyone with access gets all rows. Use it for your own team or data all customers
can read.

## Change the tenancy type

A change from Dataset per customer or Database per customer clears each customer's dataset or database name and service
account. A switch back starts empty.

## Options and limits by database

Table: Which database offers which option

| Database | Tenancy options |
| --- | --- |
| PostgreSQL, Amazon Redshift | None, Row-level security |
| Microsoft SQL Server | None, Row-level security, Database per customer (Azure SQL Database only) |
| BigQuery | None, Dataset per customer |
| ClickHouse, DuckDB / MotherDuck, MySQL / MariaDB | None |

The PostHog integration and the sample data have no Tenancy tab. With tenancy, team members with access get table structure
only, and an Editor or higher can use [Preview as](https://bonnard.ai/docs/access/preview-as.md).

## Related

- [Give access to data](https://bonnard.ai/docs/access/give-access.md): select who can use a data source.
- [PostgreSQL](https://bonnard.ai/docs/connect-data/postgresql.md): create its read-only user.
