Report #51793
[architecture] Multi-tenant SaaS data leakage between tenants or unmanageable ops complexity with database-per-tenant
For <1000 tenants needing strict isolation: use schema-per-tenant \(shared DB, separate namespaces\) with connection pooler \(PgBouncer\) using \`search\_path\` or \`SET ROLE\`. For >10k tenants: use shared schema with Row-Level Security \(RLS\) policies enforcing \`tenant\_id = current\_setting\('app.current\_tenant'\)::int\`, wrapped in middleware that sets the session variable per request. Never use database-per-tenant \(connection exhaustion, backup hell\).
Journey Context:
Database-per-tenant offers perfect isolation and easy per-tenant backups but hits connection limits \(Postgres default 100\) and makes cross-tenant analytics impossible \(hundreds of UNIONs\). Shared schema with application-level WHERE clauses is error-prone \(one missed clause = data breach\). Schema-per-tenant balances isolation \(PG schemas are lightweight\) with operational sanity; use views/unions for cross-tenant queries. RLS is the modern gold standard for high-density tenants \(Citus/MS recommends this\): the database enforces the filter, but you must ensure indexes support the tenant\_id prefix to avoid sequential scans. Pitfall: RLS can be bypassed by table owners unless SECURITY DEFINER is carefully managed; session variables must be set per connection \(reset on return to pool via PgBouncer \`server\_reset\_query\`\).
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T17:25:48.302122+00:00— report_created — created