Skip to main content

Permission and RLS issues

Permission issues often appear as permission denied, HTTP 401/403, empty query results, or failed writes. Diagnose both role grants and RLS policies.

Identify the issue type

SymptomCheck first
permission denied for tableTable and schema permissions
permission denied for sequenceIdentity sequence permissions
Query succeeds but returns an empty arrayRLS using condition mismatch
Insert or update failsRLS with check condition mismatch
Unauthenticated access failsanon role or sign-in state

Check table permissions

select grantee, privilege_type
from information_schema.role_table_grants
where table_schema = 'public'
and table_name = 'todos'
order by grantee, privilege_type;

Grant permissions as needed:

grant usage on schema public to authenticated;
grant select, insert, update on public.todos to authenticated;
grant usage, select on all sequences in schema public to authenticated;

Check RLS status

select schemaname, tablename, rowsecurity
from pg_tables
where schemaname = 'public'
and tablename = 'todos';

View policies:

select policyname, cmd, roles, qual, with_check
from pg_policies
where schemaname = 'public'
and tablename = 'todos';

Empty result diagnostics

If a query returns an empty array without an error, RLS usually filtered all rows. Check:

  • Whether the current user is signed in.
  • Whether the ownership field equals auth.uid().
  • Whether the policy uses the correct role, such as authenticated.
  • Whether the query goes through a view and whether that view bypasses RLS.
select auth.uid();

When auth.uid() is null, user-based policies deny access.

Fix recommendations

  • Design RLS before opening table permissions to frontend access.
  • Use WITH CHECK for insert and update to prevent writing data for other users.
  • Index RLS filter fields to avoid slow permission checks.
  • Put admin operations behind Cloud Functions or CloudBase Run instead of relaxing frontend RLS.

For policy examples, see Basic permissions.