Início / RLS / Erro 42501: permission denied for table · Read in English
Supabase RLS · Correção de erro
Erro 42501: permission denied for table
O role (anon, authenticated ou service_role) não tem privilégio na tabela, então o Postgres barra a query antes mesmo de o RLS rodar. Dê grant só daquela tabela, só pro role que precisa, na mesma migration que cria a tabela. Nunca resolva com grant ... on all tables.
01 Grants e RLS: duas trancas diferentes
Toda query que chega pela Data API passa por duas verificações. Os grants decidem se um role pode tocar na tabela. O RLS decide depois quais linhas. 42501 permission denied for table invoices significa que a primeira tranca falhou, então suas policies nem foram consultadas. Problema de RLS tem outra cara: zero linhas, ou new row violates row-level security policy.
02 De onde vem
Tabela criada depois da mudança de grants do Supabase
Tabelas novas não ganham mais grants automáticos pros roles da API. A primeira query numa tabela nova devolve 42501 até você dar o grant. O que mudou em 30/10 e por que importa.
Tabela em outro schema
O role também precisa de usage no schema; sem isso, a mensagem é permission denied for schema app.
O grant foi revogado ou nunca foi dado pra esse role
Por exemplo, grant pra authenticated, mas quem chama é um visitante deslogado (anon). A Data API responde 401 pra anon e 403 pra authenticated.
03 A correção: grant por tabela, com RLS na mesma migration
migration.sql
alter table public.invoices enable row level security; create policy "owner reads" on public.invoices for select to authenticated using (user_id = (select auth.uid())); -- só o role e as operações que o app realmente usa grant select on public.invoices to authenticated;
Pra tabela em outro schema, adicione também grant usage on schema app to authenticated;
04 A correção que vaza
-- não cole isso pra sumir com o erro grant select on all tables in schema public to anon, authenticated;
Some com o 42501 e libera também todas as outras tabelas de public. Qualquer uma com RLS desligado vira leitura livre pra quem tiver sua anon key pública. Confira o que cada role alcança antes e depois de qualquer grant:
check.sql
select c.relname, has_table_privilege('anon', c.oid, 'select') as anon_can_read, c.relrowsecurity as rls_on from pg_class c join pg_namespace n on n.oid = c.relnamespace where n.nspname = 'public' and c.relkind = 'r' order by 1;
Linha com anon_can_read = true e rls_on = false é tabela pública. O guia da mudança de grants tem uma versão mais rigorosa, que também pega grants de coluna e views.
Se for escrever as policies do zero, o gerador de policies RLS monta a migration com RLS, policies e só os grants necessários (em inglês).
Pegue isso antes de ir pro ar
airlock-rls é um gate de CI que quebra o build quando uma tabela vai pro ar exposta ou uma policy é permissiva: o mesmo tipo de bug, pego no CI contra um banco com as suas migrations aplicadas, antes de chegar em produção.
Ou comece pelo nextjs-supabase-starter: auth + uma tabela com RLS + um teste de isolamento, pra começar de um padrão que já vem selado.
Baixe o cheat sheet de RLS do Supabase
As regras de ouro, as armadilhas que vazam em produção, policies corretas e o teste de isolamento, numa página só (em inglês).
FAQ
O 42501 é um erro de RLS?
Não. É erro de privilégio, que acontece antes do RLS. O mesmo SQLSTATE aparece quando um insert ou update falha no WITH CHECK de uma policy, mas aí a mensagem é new row violates row-level security policy, e não permission denied for table.
Preciso dar grant pro service_role também?
Se o seu backend usa a chave service_role numa tabela nova, sim. O service_role ignora o RLS, mas continua precisando do privilégio na tabela.