BuiltSafely

Home/Supabase

Supabase

Supabase's Oct 30 change: new tables need a GRANT (don't turn off RLS)

From October 30, 2026, new public tables in existing Supabase projects aren't reachable through the Data API until you grant access. What changes, what the error looks like, and the safe fix.

  • Reviewed Oct 2026
  • 4 official sources
Sources Last checked October 16, 2026 · Sources: Supabase official changelog and docs (linked below) · Educational, not an audit

If your app talks to Supabase through supabase-js or another client library, one default changes on October 30, 2026. We'll cover what changes, what the error looks like, and how to fix it without weakening your security.

What changes

Until now, new tables in the public schema were automatically granted select, insert, update and delete for the anon, authenticated and service_role roles. That made every new table reachable through the Data API as soon as it was created (Supabase changelog).

After the change, Supabase says new tables in public "require an explicit opt-in (via a Postgres grant) before the Data API can see them" (Supabase changelog). The Data API is the auto-generated REST and GraphQL layer that supabase-js and the other client libraries call (Supabase changelog).

The dates, from the changelog (Supabase changelog):

  • April 28, 2026: new projects can opt in at creation.
  • May 30, 2026: the new behavior becomes the default for new projects, rolled out gradually.
  • October 30, 2026: the new behavior is applied to all existing projects.

What's not affected, per the changelog (Supabase changelog):

  • Existing tables. They "keep their current grants and stay reachable."
  • Other schemas. Tables in storage, auth, realtime and custom schemas keep their current grants and defaults.
  • Direct database connections. Apps that use a direct Postgres connection (psql, an ORM or a server with a connection string) aren't affected.
  • RLS. "RLS behavior remains unchanged." Grants decide whether a role can reach a table at all, and RLS decides which rows it sees.

The changelog explains why. Today AI tools, agents and scripts create tables too, often with no human reviewing the change, so it's easy to expose a table before it's protected (Supabase changelog).

Grant, enable RLS, add policies: treat them as one unit, in the same migration.
BuiltSafely Research

How the error looks

If a grant is missing, the Data API returns a Postgres 42501 error instead of failing silently. Supabase's example (Supabase changelog):

{
  "code": "42501",
  "message": "permission denied for table your_table",
  "hint": "Grant the required privileges to the current role with: GRANT SELECT ON public.your_table TO anon;"
}

Supabase's troubleshooting page notes that clients often report 42501 errors as 401 or 403 errors. It also lists other causes, such as restricted schemas, column-level restrictions and RLS blocking an insert or update (Supabase: Database API 42501 errors). So read the message. "permission denied for table" points to a missing grant. "new row violates row-level security policy" points to a policy (see our Supabase RLS guide).

To see which grants a table has, Supabase suggests (Supabase: Database API 42501 errors):

select grantee, privilege_type
from information_schema.role_table_grants
where table_name = 'your_table';

The fix: grant, enable RLS, add policies, all in one migration

Supabase recommends treating three steps "as a unit" in the same migration: grant the privileges each role needs, enable RLS, and add policies (Supabase changelog). Without the grant, "Postgres rejects the query before RLS comes into play" (Supabase changelog).

Here's what that looks like for a table where signed-in users manage only their own rows:

create table public.todos (
  id bigint generated by default as identity primary key,
  user_id uuid not null default auth.uid(),
  task text
);

-- 1. Grant only what each role needs (here: nothing for signed-out visitors)
grant select, insert, update, delete on table public.todos to authenticated;

-- 2. Keep RLS on
alter table public.todos enable row level security;

-- 3. One policy per operation
create policy "todos select own" on public.todos
  for select to authenticated using ( (select auth.uid()) = user_id );
create policy "todos insert own" on public.todos
  for insert to authenticated with check ( (select auth.uid()) = user_id );
create policy "todos update own" on public.todos
  for update to authenticated
  using ( (select auth.uid()) = user_id )
  with check ( (select auth.uid()) = user_id );
create policy "todos delete own" on public.todos
  for delete to authenticated using ( (select auth.uid()) = user_id );

The grant syntax follows the changelog's example (Supabase changelog). We've made a few deliberate changes:

  • **No anon grant here,** because signed-out visitors shouldn't reach this table. The changelog's example does grant select to anon. Only do that for data meant to be public.
  • **No service_role grant here.** The changelog's example also grants service_role. Add grant select, insert, update, delete on table public.todos to service_role; only if server-side code uses the secret key for this table.
  • **One policy per operation, with (select auth.uid()),** following the RLS guide (Supabase: RLS).

Tested October 16, 2026 against a throwaway local Supabase Postgres 17 container, with no real project involved. We ran the changelog's opt-in statements first so new tables got no default grants. Before the grant, signed-out reads and signed-in inserts failed with 42501: permission denied for table todos, along with Supabase's hint. After the block above, a signed-in user could insert and read their own row, a second user saw 0 rows, and signed-out reads still failed with 42501. The identity column needed no separate sequence grant. A table created before the opt-in kept its grants.

What not to do

When an app suddenly breaks, a quick "fix" can make things worse. Avoid these:

  • Don't disable RLS. Supabase's RLS guide warns that a table without it "is readable and writable by any role with a grant on it" (Supabase: RLS).
  • **Don't switch the frontend to the secret or service_role key.** It bypasses RLS and must never be in a browser or a shipped app (Supabase: API keys).
  • **Don't bulk-grant everything to anon without RLS and policies.** Supabase's troubleshooting page notes that granting privileges allows access through the Data API, so enable RLS and write policies to protect the data (Supabase: Database API 42501 errors).

A prompt you can give your AI tool

My Supabase app returns 42501 "permission denied for table <name>". Fix it with
explicit GRANT statements in a migration. Grant only the privileges each role
needs (anon only for data that is meant to be public). Keep row level security
enabled, and add one policy per operation (select, insert, update, delete) using
(select auth.uid()). Do not disable RLS, do not use using (true) on private data,
and do not use the service_role or secret key in frontend code. Show me the SQL
before applying it.

Always read what the tool produces before you run it. Then test with two accounts, as our Supabase RLS guide describes.

Quick checklist

  • New public tables get explicit grants in the same migration as RLS and policies (Supabase changelog)
  • anon only has grants on data meant to be public
  • RLS stays enabled, with one policy per operation (Supabase: RLS)
  • Only the publishable key is in client code (Supabase: API keys)
  • You checked the Security Advisor, which Supabase says flags affected tables before October 30 (Supabase changelog)

Your turn

Has an AI tool ever "fixed" a permission error by turning off a safety setting? Tell us what happened and how you caught it. We'll collect the patterns for a future guide.

This guide is educational and based on the vendor's public docs as of the review date. Platforms change: check the linked sources. Not a security audit. Disclaimer.

The BuiltSafely weekly

One email a week. What changed, and the one fix that matters.

Platform changes that affect the security of AI-built apps, checked against official docs. Free. Unsubscribe any time.