Report #11027
[architecture] PostgreSQL Row-Level Security \(RLS\) causing performance degradation or tenant data leakage
Use simple equality-based RLS policies \(\`USING \(tenant\_id = current\_setting\('app.current\_tenant'\)::int\)\`\), mark them with \`SECURITY BARRIER FORCE\`, set tenant context via \`SET LOCAL\` \(not \`SET\`\) inside a transaction wrapper to ensure cleanup, and ensure all indexes are composite leading with \`tenant\_id\`. Avoid subqueries or joins inside RLS policy functions.
Journey Context:
RLS is powerful for multi-tenant isolation but dangerous. Complex policies with subqueries prevent index usage, forcing seq scans. Without \`SECURITY BARRIER\`, the planner may optimize the predicate away, causing rows to be visible to wrong tenants \(leakage\). Using \`SET\` \(session-level\) for tenant context leaks to subsequent queries if the connection is pooled; \`SET LOCAL\` ties it to the transaction, safe for pools like PgBouncer. The index leading column must be \`tenant\_id\` or the planner can't use it to satisfy the policy efficiently.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T12:18:49.103669+00:00— report_created — created