iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
A PostgreSQL view can expose rows that a user’s own row-level security (RLS) policy would hide. By default, PostgreSQL checks access to the view’s underlying tables using the view owner’s privileges, and applies those tables’ RLS policies as the view owner. To make underlying access use the invoking user’s privileges and policies, define the view with security_invoker = true—while also checking the separate RLS bypass rules for superusers, BYPASSRLS roles, and table owners.
Why a regular view can show rows hidden by RLS
PostgreSQL processes views through its rewrite mechanism. For an ordinary view, access to underlying relations is ordinarily checked with the view owner’s privileges. If a base table has RLS enabled, its policies ordinarily run as the view owner too—not as the user who selected from the view. The PostgreSQL 18 documentation states that “by default, the row-level security policies of the view owner are applied” to underlying relations with RLS enabled. PostgreSQL CREATE VIEW documentation
That default can create a gap between what a user sees in a direct query and what the same user sees through a view. If the view owner’s policy permits more rows than the caller’s policy, the view can return rows the caller would not see when querying the table directly under their own role. This is why a view can appear to bypass RLS without RLS being globally disabled.
Recommended Free Tools
A tenant-policy example
Suppose accounts has a policy such as USING (tenant_id = current_setting('app.tenant_id')::int). A user querying the table directly is filtered according to the role and policy context used for that query. If a regular view is owned by a role whose policy context permits rows from every tenant, a caller may see those rows through the view because the underlying table access and policy evaluation use the view owner’s identity by default.
#1 Best Overall
This example illustrates the identity difference; the result in a real deployment depends on its roles, grants, policies, settings, and view definitions.
Which view option changes the identity?
| Option | Effect on underlying relations | What it is for |
|---|---|---|
| Default view | Underlying privileges and RLS policies ordinarily use the view owner. | Allows callers to use the view without needing the view owner’s underlying-table privileges themselves. |
security_invoker = true |
Underlying privileges and RLS policies use the invoking user, as if the relations were referenced directly in the query. | Applies caller-based access and policy checks; callers need the relevant underlying privileges. |
security_barrier = true |
Does not change which role’s privileges or RLS policies apply. | Controls predicate evaluation order to reduce information leaks through unsafe expressions. |
For caller-based table permissions and RLS, create a view with the option or alter an existing view:
Rank #2
CREATE VIEW tenant_accounts WITH (security_invoker = true) AS
SELECT account_id, tenant_id
FROM accounts;
For an existing view, the corresponding form is ALTER VIEW view_name SET (security_invoker = true). With this option, callers must have the necessary privileges on the underlying relations, as well as permission to use the view. Consult the CREATE VIEW reference for syntax and behavior on the PostgreSQL version actually installed.
security_barrier addresses a different concern: it constrains predicate evaluation to guard against information leaks caused by expressions. It is not a remedy for using the view owner’s policy identity when caller-based RLS is required. The two options control different aspects of view behavior. PostgreSQL CREATE VIEW documentation PostgreSQL rules and privileges documentation
Rank #3
RLS bypass rules still matter
security_invoker = true makes the invoking user’s privileges and policies relevant to underlying relations, but it does not cancel PostgreSQL’s general RLS bypass rules. Superusers and roles with the BYPASSRLS attribute always bypass row security. A table owner normally bypasses RLS on that table as well; ALTER TABLE ... FORCE ROW LEVEL SECURITY subjects the owner to its policies. PostgreSQL 17 row security documentation
So if an invoker is a superuser, has BYPASSRLS, or owns the base table, changing the view to invoker mode does not by itself guarantee the intended row filtering. Whether the table-owner case is subject to policies depends on whether RLS is forced.
How to audit a view-based access path
Review the complete path from the caller through the view to each protected table. Check these items together rather than treating the view option as the whole security boundary:
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →- Identify the view owner. Determine which role owns the view and whether its underlying privileges or policies are broader than intended for callers.
- Inspect the view options. Confirm whether
security_invokerandsecurity_barrierare set. They solve different problems: policy identity and predicate evaluation order, respectively. - Inspect each base table. Verify whether RLS is enabled and review the policies that apply to relevant commands and roles.
- Check role and ownership exceptions. Determine whether the view owner or caller is a superuser, has
BYPASSRLS, or owns a protected table. - Check forced RLS where needed. If a table owner is intended to be subject to policies, verify that
FORCE ROW LEVEL SECURITYis set on the table. - Follow nested views. An underlying security-invoker view retains caller-based checking when reached through an outer view, so inspect every view in the chain.
PostgreSQL’s CREATE VIEW documentation describes invoker behavior, and its row security documentation explains bypass and table-owner behavior. Match documentation to the installed major version and verify the minor release before making deployment-specific security judgments.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Keep release-specific planner fixes separate from the default
The view-owner RLS behavior is not new to PostgreSQL 18: PostgreSQL 14 documentation already described the default owner-based behavior for underlying table privileges. PostgreSQL 14 CREATE VIEW documentation
PostgreSQL 17.6 also includes a fix for CVE-2025-8713, a specific planner-time permission-check issue. In that case, a view owner’s permissions could satisfy an initial security check before a leaky function was applied to underlying table statistics; the fix moved view security checks to the start of planning. That issue is distinct from the ordinary rule determining whose RLS policies apply through a view. PostgreSQL 17.6 release notes
PostgreSQL 11.3 release notes document an older fix involving RLS bypass through selectivity estimators. It is another distinct planner interaction, not an explanation of the current default view-owner policy identity. PostgreSQL 11.3 release notes
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

