Grants for anon, authenticated and service_role
Three roles, four privileges. This is the grid the tool fills in.
The three roles
| Role | When the Data API uses it | Row level security |
|---|---|---|
anon | A visitor who is not signed in. | Applies |
authenticated | A signed-in user. | Applies |
service_role | Server-side code that uses the secret key. | Bypassed. Keep the key off the browser. |
What each access choice grants
| Choice | anon | authenticated | service_role | Policies written |
|---|---|---|---|---|
| Public read | SELECT | SELECT | SELECT, INSERT, UPDATE, DELETE | One: read every row |
| Owner only | none | SELECT, INSERT, UPDATE, DELETE | SELECT, INSERT, UPDATE, DELETE | Four: own rows only |
| Private | none | none | SELECT, INSERT, UPDATE, DELETE | None (RLS on, so nothing gets through) |
The statements
Supabase's own example grants read to visitors and full access to signed-in users and the server:
-- Read-only access for anonymous clients
grant select on table public.your_table to anon;
-- Full access for signed-in users; RLS still applies
grant select, insert, update, delete on table public.your_table to authenticated;
-- Full access for server-side code using the service role
grant select, insert, update, delete on table public.your_table to service_role;
A grant only opens the door. Enable row level security and add policies in the same migration, or a granted table is readable by anyone holding that role.
Old defaults, for comparison
On projects that still auto-expose, a new public table receives select, insert, update, delete, truncate, references, trigger and, on Postgres 17, maintain for all three roles.
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
Does service_role need a grant too?
Yes. The change revokes default privileges from service_role as well, and Supabase's example grants it explicitly. Bypassing row level security is separate from having a table privilege.
Should anon ever get insert?
Only when signed-out visitors are meant to write, such as a public contact form, and then with a policy that limits what they can insert. This tool does not write that shape.
Sources
- Supabase docs: Securing your API, read 2026-11-10
- Supabase docs: Row Level Security, read 2026-11-10
- Supabase docs: Postgres Roles, read 2026-11-10
- Supabase changelog: Breaking Change: Tables not exposed to Data and GraphQL API automatically (published 2026-04-28), read 2026-11-10
Related
- Which grant does each call need?Tick what your code does. Copy the smallest grant that makes it work.
- Which role does each Supabase key use?The key picks the Postgres role. The role needs the grant.
- Postgres ACL decoderPaste the privilege string. Get one row per role, in words.
- Grants vs row level securityTwo checks run on every request. A grant comes first.