PostgreSQL Row-Level Security
This document describes RLS in general, not the specifics of how we use it.
PostgreSQL Row-Level Security (RLS) is a built-in database feature that provides fine-grained access control by restricting which rows of a table a user can see or modify, based on defined security policies.
It acts as an additional layer on top of standard SQL privileges (GRANT/REVOKE). While table-level permissions control whether a user can access a table at all, RLS filters individual rows dynamically during SELECT, INSERT, UPDATE, and DELETE operations.
Key Characteristics
RLS is enabled per table using:
alter table table_name enable row level security;
Once enabled, access to rows requires at least one matching policy (otherwise
a default-deny behavior applies — no rows are visible/modifiable). Policies are
created with CREATE POLICY and use a Boolean expression to determine which
rows are accessible, e.g.:
current_user = ownerortenant_id = current_setting('app.current_tenant')
Policies can apply to specific commands (SELECT, INSERT, UPDATE, DELETE,
or ALL), specific roles, or be permissive/restrictive. Table owners and
superusers typically bypass RLS (unless explicitly configured otherwise).
Whole-table operations like TRUNCATE or adding foreign keys are not affected
by RLS.
Common Use Cases
- Multi-tenant applications (each tenant only sees their own data)
- User-specific data isolation (e.g., employees see only their department's records)
- Implementing authorization logic directly in the database for consistency and defense-in-depth
RLS helps enforce data privacy and security at the database level, reducing the risk of accidental or malicious over-exposure of data through application bugs or direct database access.