Supabase's Oct 30 change: what breaks, what it doesn't fix
On October 30, 2026 Supabase stops auto-exposing new public tables to the Data API. What permission denied 42501 means, how grants differ from RLS, what AI tools will do next, and a migration checklist for existing vs new tables.
On October 30, 2026, Supabase applies a platform default to every existing project: new tables in the public schema are no longer reachable through the Data API until you explicitly GRANT access. Supabase emails a final notice around October 23, so if you build with Lovable, Bolt, Cursor, Claude Code or Replit on top of Supabase, you will see this soon — either as an email, a Security Advisor warning, or a sudden 42501 error when your AI tool creates a table.
This post goes deeper than the one-paragraph summary most checklists give. It covers grants vs RLS, the exact error you will hit, what breaks and what does not, what AI coding tools tend to do next, and a practical checklist for existing tables versus new ones.
What is actually changing
Until now, when you created a table in public on a default Supabase project, Postgres automatically granted SELECT, INSERT, UPDATE and DELETE to the anon, authenticated and service_role roles. That made every new table reachable through Supabase's Data API (PostgREST and GraphQL — what supabase-js talks to) the moment it existed.
After October 30 on existing projects (and already the default on new projects since late May 2026):
- New tables in
publicstart with no Data API grants. - You must add an explicit
GRANTbeforeanonorauthenticatedcan touch them through the client. - Existing tables keep their current grants. They stay reachable exactly as they are today.
RLS does not change. Grants decide whether a role can reach a table at all. RLS decides which rows that role can see once it can reach the table. Both layers still matter.
Direct Postgres connections (ORM, server, psql) are unaffected. Almost every vibe-coded app uses the Data API, so assume you are affected.
Grants vs RLS (the part most guides skip)
Think of two locks on the same door:
| Layer | Question it answers | Typical mistake |
|---|---|---|
| Grants | Can this role (anon, authenticated, service_role) use this table through the Data API at all? |
Forgetting the grant after Oct 30 → 42501 |
| RLS + policies | Of the rows in that table, which ones may this request see or change? | RLS off, or using (true) → data leak |
Before October 30, grants were usually “already yes” for every public table. So the only lock people talked about was RLS. After October 30, a brand-new table has the grants lock closed. Your client never even reaches RLS until you open grants.
That is why this change is useful for new tables an agent creates mid-session: without a grant, the public key cannot dump the table. It is also why the change does not close tables that are already open today. Those tables already have grants, and Oct 30 leaves them alone.
For the RLS side in plain language, see Supabase Row Level Security in plain English. For a full audit of open tables you already have, see how to check if your Supabase database is exposed.
The error you will see: permission denied 42501
When a grant is missing, PostgREST returns a Postgres privilege error. Clients often surface it as a 401 or 403, but the SQL state is 42501. The body looks like:
{
"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;"
}
The hint names the role and the privilege. That is deliberate: Supabase wants agents and humans to self-correct from the error instead of guessing.
Other causes of 42501 still exist (forbidden schemas like auth/vault, custom schemas without grants, column-level privileges, some RLS insert/update cases). After Oct 30, missing table grants on new public tables become the most common one for vibe-coded apps.
See Supabase's 42501 troubleshooting guide for log queries. Quick privilege check on one table:
select grantee, privilege_type
from information_schema.role_table_grants
where table_schema = 'public'
and table_name = 'your_table'
order by grantee, privilege_type;
If anon or authenticated is missing and your browser client needs that table, you need a grant (and then RLS).
What breaks on October 30
| Situation | Breaks? | Why |
|---|---|---|
Existing public tables your app already uses |
No | Current grants stay |
New public table created after the change, no GRANT |
Yes | Data API cannot see it → 42501 |
Tables in storage, auth, realtime, or custom schemas |
No (for this change) | Defaults touched are for public |
| Direct Postgres / ORM connection | No | Not going through the Data API |
GraphQL (pg_graphql) on new ungranted tables |
Yes | Same grant gate as REST |
| AI tool that “just creates a table and queries it” | Often yes | Tool must add grants (or read the 42501 hint) |
Most shipped apps will not break on the morning of October 30. Breakage hits the next time you (or your AI tool) add a table and expect the client to query it immediately.
What it does not fix
This is the part that matters for security:
- Open tables you already have stay open. If RLS is off, or a policy is
using (true), Oct 30 does not close that door. Grants on those tables remain. - A grant without RLS is still a leak. Once you grant
SELECTtoanonon a table with RLS disabled, anyone with your public (anon / publishable) key can read it again. - AI tools will learn to add the grant. The
42501hint is copy-pasteable. Many agents will grant broad privileges and move on — sometimes without enabling RLS or writing tight policies. - Views, storage buckets and
SECURITY DEFINERfunctions are separate surfaces. This change does not redesign those.
Treat Oct 30 as “new tables start locked at the grant layer,” not as “Supabase fixed my exposed database.”
What AI coding tools will do (and how to steer them)
After the change, a typical agent flow looks like:
- Create table with SQL / MCP / CLI.
- Query it from the client →
42501. - Read the hint → run
GRANT ... TO anon, authenticated. - Query again → either works (if RLS allows it) or hits an RLS error.
- If RLS blocks, the same old failure modes appear: disable RLS, or add
using (true).
So the platform gets safer at step 1–3, and the old risk returns at step 4–5 unless you constrain the tool.
Practical prompts to keep in your project (Cursor rules, Lovable instructions, Claude project context):
When you create a table in
publicfor the Data API: (1) grant only the privileges each role needs, (2) enable RLS in the same migration, (3) add policies that useauth.uid()for user-owned rows, (4) never useusing (true)for tables with personal data, (5) never put the service role key in client code.
Supabase also documents an agent skill that includes the grants step; keep that skill (or equivalent rules) installed if you use their MCP / agent tooling.
Prefer least privilege grants. Example for a user-owned table the browser should use when signed in, with public read of nothing:
create table public.notes (
id uuid primary key default gen_random_uuid(),
user_id uuid not null references auth.users (id),
body text not null,
created_at timestamptz not null default now()
);
-- Grants: signed-in users only (adjust if you truly need anon read)
grant select, insert, update, delete on public.notes to authenticated;
grant select, insert, update, delete on public.notes to service_role;
-- no grant to anon
alter table public.notes enable row level security;
create policy "read own notes"
on public.notes for select to authenticated
using ((select auth.uid()) = user_id);
create policy "insert own notes"
on public.notes for insert to authenticated
with check ((select auth.uid()) = user_id);
create policy "update own notes"
on public.notes for update to authenticated
using ((select auth.uid()) = user_id)
with check ((select auth.uid()) = user_id);
create policy "delete own notes"
on public.notes for delete to authenticated
using ((select auth.uid()) = user_id);
Bundle grant + RLS + policies in the same migration. A grant alone is not a security model.
Migration checklist (existing vs new)
A. Before October 30 (or right after the final email)
- Inventory exposed tables. In the dashboard, check the Data API exposure badge / Security Advisor. Or list grants:
select table_name, grantee, privilege_type
from information_schema.role_table_grants
where table_schema = 'public'
and grantee in ('anon', 'authenticated', 'service_role')
order by table_name, grantee, privilege_type;
Fix RLS on tables you already expose. Oct 30 will not do this for you. Run the checks in our exposed database guide: RLS off,
using (true)policies, neighbour tests with two accounts.Optional: adopt the new default early. If you want new tables locked now, run Supabase's revoke-default-privileges SQL in the SQL Editor (from their changelog / securing your API docs). Existing objects keep their grants; only future objects change.
Update AI / migration templates so every new table ships with grants + RLS + policies.
B. After October 30, when you add a table
- Create the table.
GRANTonly what each role needs (often: noanon, limitedauthenticated, fullservice_roleon the server only).ALTER TABLE ... ENABLE ROW LEVEL SECURITY.- Create policies.
- Test signed-out and as two different users.
- If you see
42501, read the hint — grant that privilege, then re-check RLS. Do not “fix” by turning RLS off.
C. If you opted in early and something broke
ALTER DEFAULT PRIVILEGES only affects future objects. Tables created after a revoke stay ungranted until you grant them. Supabase's changelog has rollback SQL: restore defaults for future tables, bulk-grant existing public tables if needed, then revoke again on tables that should stay private.
Quick FAQ
Do I need to re-grant every existing table on Oct 30?
No. Existing tables keep their grants.
Will my Lovable / Bolt app go down on Oct 30?
Unlikely, if you are not creating new tables that day. The risk is the next schema change.
Is a grant the same as making a table public?
A grant to anon makes the table reachable with the public key. Whether rows leak depends on RLS. Grant + RLS off = fully readable.
Should I grant everything to anon “so the app works”?
No. Grant the minimum. Many tables only need authenticated. Public marketing content is one of the few cases for anon SELECT.
Where do code-level mistakes still hide?
Auth on routes, neighbour-readable rows, webhooks, secrets in server code. A URL scan catches exposed tables and keys; the $79 Launch Audit reviews the GitHub repo when you handle payments or personal data.
What to do this week
- Read Supabase's email when it lands (~23 Oct) and open Security Advisor.
- Audit existing tables for RLS — Oct 30 will not save you there.
- Teach your AI tool the grant + RLS + policy trio before you create the next table.
- When
42501appears, follow the hint, then verify policies — do not disable RLS to silence errors.
Scan your app
Paste your app URL into the free Greenlight Scan. It checks from the outside (counts only on database probes — it does not download your rows) for open Supabase tables, leaked keys and other high-signal issues. The $19 Full Scan unlocks every finding with a fix prompt for your AI tool. If you are about to launch with payments or personal data, the $79 Launch Audit reviews the GitHub code for the problems a URL scan cannot see.
Check your own app in about 2 minutes.
Scan my app freeThe Friday leak report
One short email a week: the newest ways AI-built apps leak data, and the one-line fix for each. No spam, unsubscribe any time.