Report #14946
[architecture] Selecting between row-level security, schema-per-tenant, and database-per-tenant for SaaS multi-tenancy
For <1000 tenants with strict isolation requirements, use schema-per-tenant with PostgreSQL and SET search\_path per connection \(ensuring connection pooler supports session-level settings\). For >1000 tenants or simpler isolation, use shared tables with Row-Level Security \(RLS\) policies and tenant\_id columns, enforcing policies with USING \(tenant\_id = current\_setting\('app.current\_tenant'\)::UUID\). Avoid database-per-tenant due to connection pool exhaustion.
Journey Context:
Database-per-tenant provides maximum isolation but hits PostgreSQL's max\_connections \(~100\) rapidly and complicates backups. Schema-per-tenant offers logical isolation but requires running migrations across N schemas \(slow at scale\) and careful handling of search\_path in pooled connections \(PgBouncer transaction pooling breaks session settings\). Shared-table with RLS is most scalable but vulnerable to tenant enumeration attacks if RLS policies are bypassed \(e.g., via security definer functions\) and requires all queries to go through the tenant context. The choice is irreversible without migration downtime.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T22:48:25.378525+00:00— report_created — created