Report #16844
[architecture] Schema-per-tenant causes connection pool exhaustion and DDL management nightmares with thousands of tenants
Use PostgreSQL Row Level Security \(RLS\) with a shared schema: add a tenant\_id column to every table, create policies that compare tenant\_id to current\_setting\('app.current\_tenant'\)::UUID, and set the tenant context via SET LOCAL at connection start or through connection pooler injectors like PgBouncer.
Journey Context:
Schema-per-tenant offers strong isolation and easy backup/restore per customer, but Postgres catalogs bloat with thousands of schemas, connection limits become bottlenecks, and migrations require altering thousands of schemas. Shared-schema with application-level filtering risks tenant data leakage through forgotten WHERE clauses. RLS provides defense-in-depth: policies are enforced at the database layer regardless of application bugs. The challenge is securely setting the tenant context—SET LOCAL ensures it resets at transaction end, preventing cross-tenant leakage in pooled connections. Some worry about RLS performance overhead, but modern Postgres optimizes it well; the bigger risk is complex policies preventing index usage.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T03:48:44.315848+00:00— report_created — created