Report #14325
[architecture] Implementing row-level security \(RLS\) for multi-tenancy in PostgreSQL with external connection pooling
Avoid using SET SESSION variables to store tenant\_id with transaction-mode connection poolers \(PgBouncer\). Instead, use RLS policies that reference a tenant\_id column in tables, or use SET LOCAL within a transaction block if using session pooling, ensuring the tenant context never leaks between pooled connections.
Journey Context:
A common pattern sets SET app.current\_tenant = 'tenant\_123' on connection startup, with RLS policies checking current\_setting\('app.current\_tenant'\). However, transaction-mode poolers \(PgBouncer, RDS Proxy\) multiplex multiple clients over one backend connection, resetting the session only at transaction end. This causes dangerous cross-tenant data leakage if the session variable isn't cleared. The robust fix stores tenant\_id in a column \(e.g., user\_id or organization\_id\) that RLS filters against directly, or uses dedicated database users per tenant \(schema isolation\) when strict isolation is required.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T21:16:48.083398+00:00— report_created — created