Supabase Permission Denied for Table (42501): The Fix

Error 42501 means the role making the request (usually anon or authenticated) has no GRANT on that table. Add only the grant you need and keep RLS on.

Gary 路 Published 路 Updated 路 8 min read

Four-step card titled Supabase permission denied (42501): read the hint, check the table's grants, grant only what's needed, keep RLS on.
On this page
  1. What does "permission denied for table" mean in Supabase?
  2. Why did this start happening?
  3. What does "permission denied for schema public" mean in Supabase?
  4. How do you fix Supabase 42501 step by step?
  5. 1. Read the hint
  6. 2. Check which grants the table has
  7. 3. Grant only what the feature needs
  8. 4. Make sure RLS is on and has policies
  9. 5. Retry and confirm
  10. What does a before and after look like?
  11. What quick fixes should you avoid?
  12. Why does it fail on my local stack or preview but work in production?
  13. What if I built the app with an AI tool?
  14. How can you check which tables still need grants before Oct 30?
  15. Where should you go next?
  16. FAQ

Short answer: Supabase "permission denied for table" (Postgres error 42501) means the role making the request, usually anon or authenticated, has no GRANT on that table. Since Supabase's change, new tables in the public schema aren't reachable through the Data API until you grant access, and the change reaches every existing project on Oct 30, 2026. The fix is one line, for example grant select on public.your_table to authenticated;, with row level security left on.

By Gary, Greenlight 路 Last checked against the Supabase changelog and docs: Oct 20, 2026 路 Drafted with AI tools and reviewed before publishing.

This page is the fix for the error itself. For the full background on the change and a checklist, read our main guide: Will Supabase's October 30 change break your app?

Table names in this guide (like notes, posts or your_table) are made-up examples. Swap in your own.

What does "permission denied for table" mean in Supabase?

When a grant is missing, the Data API (PostgREST, which supabase-js calls) returns an error like this, taken from Supabase's own changelog (Supabase changelog (external)):

JSON

{
  "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;"
}

Code 42501 is Postgres's "insufficient privilege" error. Supabase's troubleshooting page says clients often report it as a 401 or 403, and that "permission denied for table your_table" means the querying role may not have the privilege for that operation (Supabase docs (external)).

Why did this start happening?

Supabase used to grant select, insert, update and delete on every new public table to the anon, authenticated and service_role roles automatically. Supabase changed that default in stages (Supabase changelog (external)):

DateWhat changed
Apr 28, 2026Optional at project creation
May 30, 2026Default for new projects (gradual rollout)
Oct 30, 2026Applied to all existing projects

Two details matter. Existing tables keep their current grants, so only tables created after the change reaches your project are affected. And if your app only talks to Postgres over a direct connection (psql, an ORM or a server connection string), you aren't affected at all (Supabase changelog (external)).

What does "permission denied for schema public" mean in Supabase?

It's the same 42501 error one level up. In Postgres, a role needs the USAGE privilege on a schema before it can reach any table inside it, even a table it has grants on (PostgreSQL docs (external)). Supabase projects normally give anon, authenticated and service_role usage on public, so this message usually means that usage was revoked, or the table lives in a custom schema the roles were never given. The fix is the schema grant, then the table grants below:

SQL

grant usage on schema public to anon, authenticated;

If the schema is your own (not public), use its name, and remember a custom schema also has to be exposed in your project's Data API settings before supabase-js can call it.

How do you fix Supabase 42501 step by step?

1. Read the hint

The hint field names the missing role and privilege. Treat it as a starting point, not an order: the example hint grants to anon, which may be wider than you want.

2. Check which grants the table has

Run this in the SQL editor (Supabase docs (external)):

SQL

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

No rows for anon or authenticated means the Data API can't reach the table for those roles.

3. Grant only what the feature needs

Decide who should use the table and what they should do with it. For a private table that signed-in users read and write:

SQL

grant select, insert, update, delete on table public.your_table to authenticated;

For a read-only public table, such as published blog posts:

SQL

grant select on table public.posts to anon, authenticated;

The privilege names come from the PostgreSQL GRANT command (PostgreSQL docs (external)). Our guide to which grants anon, authenticated and service_role need has a role-by-role table.

4. Make sure RLS is on and has policies

SQL

alter table public.your_table enable row level security;

Supabase's docs say that granting privileges opens the table to the Data API, so you should enable RLS and write policies to protect the data (Supabase docs (external)). A grant without RLS lets that role reach every row. New to policies? Start with what is Supabase RLS?

5. Retry and confirm

Reload the app or repeat the request. If you now get an empty list instead of an error, the grant worked and RLS is filtering rows; check your policies next. That difference is explained in Supabase GRANT vs RLS.

What does a before and after look like?

A worked example with a new notes table (an example) created after the change. Each row shows what a signed-in user would get, based on how Supabase describes grants and RLS:

StepRequest as a signed-in userResult
Table created after the change, no grantselect * from notes via supabase-js42501 permission denied
grant select ... to authenticated added, RLS offsameevery user's notes (unsafe)
RLS on, "read own notes" policysameonly that user's notes

The middle row is the trap. The error goes away, the app "works", and every signed-in user can read every note.

What quick fixes should you avoid?

  • Turning RLS off. It doesn't fix 42501 (grants are a separate layer), and once you add a grant it exposes every row.
  • grant all ... to anon. It hands the public key every table privilege, including truncate and trigger, which a browser should never need (PostgreSQL docs (external)). Grant select, insert, update or delete individually.
  • Using the service role key in the browser. It bypasses RLS (Supabase docs (external)). If it ever shipped to the client, follow our service role key guide.
  • Re-enabling auto-exposure everywhere. The change exists so tables aren't exposed before they're secured. Add grants per table in your migrations instead.

Why does it fail on my local stack or preview but work in production?

When your schema is rebuilt from migrations, every table is created fresh, so tables lose the grants the old default used to add. See Supabase db reset permission denied for the migration fix.

What if I built the app with an AI tool?

The changelog calls this out: if an AI coding tool, CLI script or Management API call creates tables and expects them to be reachable, you need to act (Supabase changelog (external)). Our plain-English guide is Lovable or Bolt app says permission denied.

How can you check which tables still need grants before Oct 30?

Supabase says Security Advisor will flag affected tables and that it will email active projects (Supabase changelog (external)). You can also use our Oct 30 checker and the checklist in our Oct 30 change guide.

Where should you go next?

Next, decide which role gets what with Supabase grants for anon and authenticated, and write policies with Postgres row level security: a Supabase guide. If a secret key ever reached your frontend, see Supabase service role key exposed?. Building with AI tools? Our Lovable launch checklist and what is vibe coding? cover the rest of a pre-launch pass, and the hub for this change is Will Supabase's October 30 change break your app?

FAQ

Does this affect tables I already have? No. Supabase says existing tables keep their current grants and stay reachable.

Is the anon key the problem? No. The key is meant to be public; see is my Supabase anon key safe?. The role behind it just has no grant on the new table.

Does 42501 always mean a missing grant? No. Supabase's docs list other causes, such as querying restricted schemas like auth or a custom schema that isn't exposed.

I get no error, just empty results. Is that the same issue? No. Empty results with no error usually mean RLS is on and no policy matches the user.

Sources

On this site

Related posts

Greenlight is independent and not affiliated with or endorsed by Supabase, PostgreSQL, Lovable or Bolt. Product names are used only to identify the tools this guide is about. Code is example SQL; test it on a copy of your project before running it in production. This page is general information, not professional security advice, legal advice, a security audit or a guarantee. Check your own setup against the vendor's current docs.