Row-level security (RLS)
What is row-level security (RLS) in PostgreSQL?
Row-level security lets a table decide, row by row, which rows each role can see or change, using policies created with CREATE POLICY.
Row-level security (RLS) restricts which rows a query can return or modify, separately for each role. You turn it on for a table with ALTER TABLE ... ENABLE ROW LEVEL SECURITY and then add policies with CREATE POLICY. A policy's USING expression filters the rows a role can see, and a WITH CHECK expression decides which new or updated rows are allowed.
When RLS is on and no policy applies, PostgreSQL uses a default-deny policy: no rows are visible or can be modified. Superusers and roles with the BYPASSRLS attribute always bypass row security, and table owners normally do too unless the table is set to FORCE ROW LEVEL SECURITY. Test your policies as the role your application actually connects with.
Example
The example turns on RLS for a table, adds a policy that compares the owner column with current_user, and queries the table as the role alice. Only alice's row comes back. The setup runs as a superuser, which bypasses RLS, so the final query switches roles first.
CREATE TABLE notes (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
owner text NOT NULL,
body text NOT NULL
);
INSERT INTO notes (owner, body) VALUES ('alice', 'hello'), ('bob', 'hi');
ALTER TABLE notes ENABLE ROW LEVEL SECURITY;
CREATE POLICY notes_owner ON notes USING (owner = current_user);
CREATE ROLE alice;
GRANT SELECT ON notes TO alice;
SET ROLE alice;
SELECT * FROM notes;
RESET ROLE;Plain SQL for stock PostgreSQL 16 or 17, no extensions needed. Run it in an empty database you can throw away.
Sources
Official PostgreSQL documentation (in English).