Permission denied for schema public
The role cannot enter the schema, so table grants never get looked at.
Three levels, checked in this order
| Level | Statement that opens it | Error when it is missing |
|---|---|---|
| 1. Schema | grant usage on schema public to anon, authenticated, service_role; | 42501, permission denied for schema public |
| 2. Table | grant select on public.your_table to authenticated; | 42501, permission denied for table your_table |
| 3. Rows | create policy ... on public.your_table | No rows on read. On write, 42501 with a row-level security message. |
Fixing level 1 often reveals level 2. That is progress, not a new bug.
Which role is locked out?
select
n.nspname as schema,
has_schema_privilege('anon', n.oid, 'usage') as anon,
has_schema_privilege('authenticated', n.oid, 'usage') as authenticated,
has_schema_privilege('service_role', n.oid, 'usage') as service_role
from pg_namespace n
where n.nspname = 'public';
How a project loses schema usage
The public schema a database starts with lets every role in. A schema that was dropped and created again does not. We ran exactly that in our test: after drop schema public cascade; create schema public; a table that was granted to anon, authenticated and service_role still answered permission denied for schema public for all three, until usage was granted.
We have not verified which migration tools drop the schema on reset. If yours does, put the usage grant in the first migration.
The fix
grant usage on schema public to anon, authenticated, service_role;
This lets the roles into the schema and nothing more. Each table still needs its own grant, row level security and policies. Paste your tables into the tool below for those.
If the schema is not public
| Schema in the error | What Supabase documents |
|---|---|
auth, vault | API roles cannot access these schemas. The restriction is intentional. |
| A schema you created | Grant usage on it to the API roles and expose it in the API settings. See the custom schemas guide under Sources. |
Write the fix for your tables
One table is free. The whole schema with a rollback file is $9 one-time.
Waiting for a paste.
Who can reach each table
Your tables show up here, one row each, with a choice of who can reach them.
Parsed in your browser. Your SQL is never uploaded, and no site or database is scanned.
Questions
Is it safe to grant usage on public to anon?
Usage only lets a role look up objects in the schema. It does not let the role read any table. Tables are protected by their own grants and by row level security.
I granted usage and now get "permission denied for table".
That is the next level. The schema is open, and the table has no grant for the role. Grant the table, enable row level security and add policies.
Sources
- Supabase knowledge base: Database API 42501 errors (marked updated 2026-11-03), read 2026-11-10
- Supabase docs: Using Custom Schemas, read 2026-11-10
- PostgreSQL manual: Privileges, read 2026-11-10
- Our own test: the behaviour the reference pages describe, run against PGlite, read 2026-11-10
Related
- Prisma tables return "permission denied for table"Prisma made the table, so the API roles were never granted. Here is the proof and the fix.
- Every cause of 42501 on Supabase42501 means "insufficient privilege". Match your message to a row.
- Go back to automatic exposureSupabase documents the SQL. Read what it re-opens before you run it.
- Free migration template and grants auditTwo .sql files. One creates a table the right way. One shows what every table grants today.