# PostgreSQL's row_security GUC explained: it errors, not disables, row-level security

> **Key takeaway:** The PostgreSQL row_security parameter does not disable row-level security but instead raises an error when a policy would apply, a critical distinction for backup integrity and operational security.

**Published:** 2026-11-01T14:00:00+00:00 
**Source:** Planet PostgreSQL 
**Category:** databases-storage 
**Canonical URL:** https://fosswire.org/news/postgresqls-rowsecurity-guc-explained-it-errors-not-disables.html 

## Summary
PostgreSQL consultant Christophe Pettus has published a detailed technical explanation of the row_security configuration parameter, clarifying a common and dangerous misconception among database administrators. The parameter, defaulting to on and settable by any role, does not control whether row-level security policies are enforced; rather, when set to off, it causes queries to fail with SQLSTATE 42501 if they would touch a table protected by RLS policies. The actual mechanism for bypassing row-level security is the BYPASSRLS role attribute, available only to superusers or roles explicitly granted it.

This behavior has significant operational consequences for backup workflows. pg_dump automatically sets row_security = off to ensure dumps contain complete tables or fail visibly rather than silently omitting rows. The --enable-row-security flag merely suppresses the error by allowing filtered dumps, which can produce incomplete backups with exit code zero. This explains recurring support issues with pg_cron's cron.job table on managed PostgreSQL services like Azure Database for PostgreSQL and Supabase, where administrative roles lack BYPASSRLS.

## How row_security interacts with the query rewriter and backup tools
- **Rewriter-level enforcement:** The row_security check executes once per table reference in the query rewriter, before planning, meaning even EXPLAIN, SELECT 1 FROM docs WHERE false, and COPY docs TO STDOUT trigger the error.
- **View ownership semantics:** Queries through views are checked as the view's owner; a view owned by the table owner passes through without error, while other views fail naming the base table, potentially exposing table names the querying role cannot otherwise see.
- **Plan cache invalidation:** The plan cache records the row_security setting with rewritten queries, causing prepared statements and PL/pgSQL cached plans to fail after SET row_security = off and preventing any cached plan reuse under that setting.
- **pg_dump's design rationale:** The parameter exists primarily for pg_dump, which sets it to guarantee backups are either complete or visibly broken; the 2014 commit message explicitly states this prevents the worst-case scenario of silently partial restores.
- **COPY FROM restriction:** COPY FROM refuses policy-protected tables outright, making pg_restore --enable-row-security only functional for dumps taken with --inserts, not standard COPY-format dumps.

## Why it matters
This clarification is essential for PostgreSQL administrators on managed services where superuser access is restricted, as the recurring pg_cron backup failures on Azure and Supabase demonstrate. Misunderstanding row_security as a toggle rather than an alarm leads operators to use --enable-row-security as a workaround, inadvertently creating incomplete backups that appear successful until a restore reveals missing tenant data.