Key takeaways
- Supabase's schedule applied the change to existing projects on October 30, 2026: new tables in the public schema are no longer granted to anon, authenticated and service_role. New projects have worked this way since May 30.
- Tables you already have keep their grants and keep working. Only tables created after the change are affected.
- A new table without grants fails with error 42501, "permission denied for table", in supabase-js, the REST API and GraphQL.
- The fix is one grant per role in the same migration that creates the table, next to row-level security and its policies.
- Grants decide whether a role can reach a table at all; RLS policies decide which rows it sees. You need both.
Pricing an app? Try the free app cost calculator or get a range for your project in the instant quote.
From October 30, 2026, a table you add to an existing Supabase project is invisible to your app until you grant it. Supabase used to give every new table in the public schema to the anon, authenticated and service_role roles automatically. It now leaves that to you. Tables you already have keep working; a table created after the change returns permission denied for table until its migration includes the grants.
To see which tables in your migrations are affected, paste them into the free Supabase October 30 grants checker. It runs in your browser and never uploads your SQL.
What changes, and when
Supabase announced the change in its changelog on April 28, 2026:
| Date | What happens |
|---|---|
| April 28, 2026 | New projects can opt out of exposing new tables when they are created |
| May 18, 2026 | pg_graphql is no longer enabled by default |
| May 30, 2026 | New projects stop exposing new tables by default (rolled out over a few weeks) |
| October 30, 2026 | The same default applies to all existing projects |
What changes is Postgres’s default privileges in the public schema. Before, every new table was granted select, insert, update, delete to anon, authenticated and service_role, and new sequences got usage, select. The hosted change removes those two defaults. The changelog names the setting both “Automatically expose new tables” and “Automatically expose new tables and functions”, but its opt-in SQL covers tables and sequences only. Without those defaults, the Data API (REST at /rest/v1 and GraphQL at /graphql/v1) can’t see a new table until a role is granted on it.
Functions are the part to watch. Supabase’s Securing your API guide says that on existing projects new functions in public also get execute for anon, authenticated and service_role, and that Postgres separately grants execute on every new function to PUBLIC through a global default. A revoke limited to one schema, including the opt-in SQL below, can’t remove that default, and a Supabase staff member said in August 2026 that the change doesn’t handle it, because it is the PostgreSQL default and can only be revoked globally, adding that it “needs further discussion and handling”. So a new function stays callable by every role, signed-out visitors included, until you revoke execute from both public and anon. The October 30 change does not close that gap for you. Grant execute explicitly to the roles that should call each function you use through the Data API. (The local CLI also revokes the Data API roles’ default privileges on new functions; see below.)
What doesn’t change:
- Existing tables keep the grants they already have.
- Row-level security works exactly as before. RLS and grants are separate checks, so see why data can still be exposed with RLS on.
- Other schemas, such as
auth,storageandrealtime, aren’t affected. - Direct Postgres connections (psql, an ORM or your own server) aren’t affected. The change matters if your app talks to Supabase through supabase-js, REST or GraphQL.
The symptom
A request to a new table without grants fails with Postgres error 42501. This is the response Supabase’s changelog shows, with its example table renamed to projects:
{
"code": "42501",
"message": "permission denied for table projects",
"hint": "Grant the required privileges to the current role with: GRANT SELECT ON public.projects TO anon;"
}
In supabase-js, the error object comes back filled and data is null. If the app doesn’t show errors, users simply see an empty screen or a button that does nothing. The same query works in the SQL editor, which runs as postgres, the role that owns the table and has every privilege, and fails in the app. That is why this one can be confusing.
The fix: grant in the same migration
Put the grants in the migration that creates the table, so every environment (local, staging, production) ends up the same. This is the pattern from Supabase’s Securing your API guide:
create table public.projects (
id uuid primary key default gen_random_uuid(),
user_id uuid not null references auth.users on delete cascade,
name text not null
);
-- 1. Who can reach the table at all
grant select, insert, update, delete on table public.projects to authenticated;
grant select, insert, update, delete on table public.projects to service_role;
-- 2. Which rows they can see and change
alter table public.projects enable row level security;
create policy "Owners can read their projects"
on public.projects for select
to authenticated
using ((select auth.uid()) = user_id);
create policy "Owners can add projects"
on public.projects for insert
to authenticated
with check ((select auth.uid()) = user_id);
create policy "Owners can update their projects"
on public.projects for update
to authenticated
using ((select auth.uid()) = user_id)
with check ((select auth.uid()) = user_id);
create policy "Owners can delete their projects"
on public.projects for delete
to authenticated
using ((select auth.uid()) = user_id);
A few details are easy to miss:
- Grant only what each role needs. A table that signed-out visitors should never touch gets no
anongrant at all. Public read-only data getsgrant select ... to anonand nothing more. serialcolumns need a sequence grant. If the table usesserialorbigserialrather than an identity column or a UUID, inserts also needgrant usage, select on sequence public.projects_id_seq to authenticated;.- Functions need
executehandled both ways. For a function your app calls withrpc(), usegrant execute on function public.your_function() to authenticated;. Every role can still call it through thePUBLICdefault, so unless signed-out visitors should call it, also runrevoke execute on function public.your_function() from public, anon;. Asecurity definerfunction runs with its owner’s rights and bypasses RLS, so review those first. - Grants are not a replacement for RLS. With a grant and RLS off, any signed-in user, or anyone at all if
anonis granted, can read every row. Turn RLS on for every exposed table, then check what the policies allow with the free Supabase RLS policy checker.
Local development already works this way
If local tables work but the hosted project doesn’t (or the other way round), check your Supabase CLI version. Since Supabase CLI v2.106.0 (June 11, 2026), supabase start and supabase db reset revoke the default Data API privileges for new tables, sequences and functions in public, because [api].auto_expose_new_tables in config.toml now defaults to false.
So a migration without grants fails locally with the same 42501 error. That’s useful: it shows the problem before you deploy. Setting auto_expose_new_tables = true brings the old behaviour back for now, but the CLI release notes say the flag is deprecated and scheduled for removal on October 30, 2026. Add the grants to the migration instead.
Check your project for missing grants
- List your newest migrations (
supabase/migrations/in the repo, or the SQL your AI tool generated) and look forcreate tablestatements inpublicwithout matchinggrantlines. - Run them through the grants checker. It lists each table that would need a grant, each table with RLS off, and each policy that lets anyone in.
- Test as a real user, not as
postgres. Sign in to the app with a normal account and use each feature that touches a new table. The SQL editor bypasses grants, so it won’t show the problem. - Switch the default yourself if new tables still get grants. Supabase’s schedule applied the change to existing projects on October 30, 2026. If a new table in your project still gets grants on its own, the changelog gives the SQL to run in the SQL editor; it changes only tables and sequences created afterwards:
alter default privileges for role postgres in schema public revoke select, insert, update, delete on tables from anon, authenticated, service_role; alter default privileges for role postgres in schema public revoke usage, select on sequences from anon, authenticated, service_role;
Doing it on a staging project first shows you any missing grants before they reach production.
For every other dated Apple, Google Play and Firebase requirement in 2026 and 2027, see App Store and Google Play deadlines for 2026 and 2027.
Grants are one item on a longer list. The Supabase security review before launch covers the rest: keys, RLS policies, views and functions, storage, Edge Functions, auth email and backups.
If you use Lovable, Bolt, v0 or another AI builder
These tools write SQL migrations for you, and nothing in a generated migration warns you that the defaults changed. Read each new migration before you approve it: every create table in public should be followed by a grant for each role that needs it and by enable row level security. If you can’t read the SQL yourself, paste it into the checker; it flags missing grants in plain language. On Lovable, the grants are one of seven problems to check before launch, Bolt has its own pre-launch checklist, and so do v0 apps that use Supabase.
If your AI-built app has more than a couple of these problems, or users are already seeing empty screens, App369’s AI-Built App Rescue starts with a $450 Launch Check. Within 3 business days of read-only access, you get each issue it finds in sign-in, data access, payments and deploys, ranked, with where it is, plus a fixed price to fix the worst of them. The $450 is credited to that fix. If you’re weighing other options, see who to hire to finish a vibe-coded app.
Want this done at a fixed price?
Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.
Frequently asked questions
- Did the October 30 change break my app?
- Not on the day itself. Supabase says existing tables keep their current grants, so what worked before keeps working. The risk is the next table you create: without a grant, every request to it from supabase-js, REST or GraphQL fails with "permission denied for table" (error 42501). Add the grants in the migration that creates the table.
- Why does Supabase say "permission denied for table" on a table I just created?
- Supabase's Data API change applies to new projects from May 30, 2026 and to existing projects from October 30, 2026. New tables in the public schema then have no grants for anon, authenticated or service_role. Add the grants in the migration that creates the table.
- Is this the same as a row-level security error?
- No. A missing grant fails every request with "permission denied for table". RLS blocks differently: reads return no rows, updates and deletes on hidden rows change nothing, and a blocked insert fails with "new row violates row-level security policy".
- Can I turn the change off for an existing project?
- Supabase documents a rollback that restores the old default privileges, but that exposes every future table again. Granting each table on purpose is safer.
- Does this affect Lovable, Bolt or other AI-built apps?
- It affects any project that reaches new tables through the Data API (supabase-js, REST or GraphQL), whoever wrote the migrations, which covers most AI-built apps. Apps that only use a direct Postgres connection are not affected. Check new migrations for a grant per role before they run.
Sources
- Supabase CLI v2.106.0 release notes (June 11, 2026)
- Supabase changelog: tables not exposed to Data and GraphQL API automatically (April 28, 2026)
- Supabase docs: Securing your API
- Supabase GitHub discussion 45329: staff replies on existing tables and function grants (April to August 2026)
- Supabase docs: Database functions
- PostgreSQL docs: GRANT
Related Resources
Related guides
AI API Errors: 7 OpenAI, Claude, Gemini and MCP Fixes (2026)
AI feature broken by a 401, 429 or 529, or an MCP connector that won't connect? 7 OpenAI, Anthropic, Gemini and MCP errors, what each means and how to fix it.
Read moreApp Store and Google Play Rejections: 13 Fixes (2026)
App rejected by Apple or Google Play? 13 rejections, from Guidelines 2.1, 4.3 and 5.1.1 to Play's Data safety form and 12-tester rule, and how to fix each.
Read more