Guide Supabase

Seeing a permission denied (42501) error after Oct 30? Here's the safe fix

Short answer

Your app worked yesterday. Now a new table returns permission denied for table ... (Postgres code 42501). Your data is likely fine. Here's what changed and how to fix it without opening your data to everyone.

What changed, and who it hits

From Oct 30, 2026, Supabase plans to stop automatically exposing new tables in the public schema of existing projects to the Data API (the auto-generated REST and GraphQL API your Lovable, Bolt, Replit or Cursor app calls). Once the change reaches your project, new tables need an explicit grant. New projects have defaulted to this since the May 30, 2026 rollout, which Supabase rolled out gradually over a few weeks.

A new table stays out of reach of the API until you give access with a Postgres grant. In Supabase's words: "If the grant is missing, Postgres rejects the query before RLS comes into play."

It affects you if you (or your AI builder) add a new table after the change. Tables in storage, auth and other schemas aren't affected, and neither are apps that only use a direct Postgres connection.

Source: Supabase changelog: Tables not exposed to Data and GraphQL API automatically

The fix, step by step

1. Find the table that's failing

  • Read the error in your browser console or network tab and look for the table name.
  • In the Supabase dashboard, open Advisors, then Security Advisor. Supabase says it flags the tables this change affects. The fix SQL is below.

2. Grant only what the table needs, to the right role

Ask: who should use this table, and what should they do with it? Then grant just that, on just that table. Replace your_table.

-- Signed-in users read and write their own rows (typical app tables)
grant select, insert, update, delete on public.your_table to authenticated;

-- Only if the data is really meant to be public (e.g. a public product list)
grant select on public.your_table to anon;

-- Server-side code using the service role key
-- (service_role bypasses RLS, so keep that key server-side)
grant select, insert, update, delete on public.your_table to service_role;

If the table uses a serial id, also run grant usage, select on sequence public.your_table_id_seq to authenticated;. identity columns don't need this.

If a table only needs reading, grant only select. Skip the anon line unless signed-out visitors should see that data.

3. Make sure RLS is on, with real policies

A grant lets a role reach the table; RLS decides which rows it sees. A grant on a table with RLS off opens every row to that role.

alter table public.your_table enable row level security;

-- Example: users see and change only their own rows
create policy "Users read own rows"
  on public.your_table for select
  to authenticated
  using ((select auth.uid()) = user_id);

create policy "Users insert own rows"
  on public.your_table for insert
  to authenticated
  with check ((select auth.uid()) = user_id);

Adjust user_id to your owner column, and add update/delete policies if your app needs them (update needs both using and with check on (select auth.uid()) = user_id). Without them, the update/delete grant does nothing under RLS.

4. Re-test signed out and signed in

  • Signed out: private tables should return nothing or an error, not data.
  • Signed in as user A: you see your own rows and the app works again.
  • Signed in as user B: you can't see user A's rows.

Please avoid these "quick fixes"

  • grant all ... to anon: this hands every signed-out visitor every privilege on the table. If RLS is weak or off, anyone with your project URL could read, change or delete data.
  • Turning RLS off to make the error go away: it may "work", but it can expose every row to anyone who can reach the API.
  • Pasting AI-generated SQL that grants broadly across the whole schema without reading it first.

More help

Our earlier deep-dive covers the same error in more detail: Supabase 42501 permission denied after Oct 30

Want a second pair of eyes?

Run the free public check on your app, or get the $49 Database Check: you run our read-only script in your SQL editor and send us the results. No passwords, no keys, no login to your account. You get a plain red, yellow and green report covering every table and storage bucket, with the order to fix things in. Get the $49 Database Check

AI agents run the checks and a human engineer reviews and approves every report before you get it. It's not a penetration test or a security guarantee.

Sources