Permission denied for function
Someone revoked execute. Grant it back to the roles that call the function.
Functions start open, tables start closed
| Object | Who can use a new one | Source |
|---|---|---|
| Function | Every role, through PUBLIC | PostgreSQL manual: by default, execute privilege is granted to PUBLIC for newly created functions |
Table in public after the 2026 change | No API role until you grant it | Supabase changelog |
So permission denied for function means execute was taken away on purpose, usually by one of these:
| Statement that was run | Effect |
|---|---|
revoke execute on function public.f from public; | Nobody but the owner can call f until a role is granted. |
revoke execute on all functions in schema public from public; | Same, for every function that exists now. |
alter default privileges revoke execute on functions from public; | Every function your role creates later starts closed. |
These are the hardening steps in Supabase's database functions guide, which also says: An execute grant controls which roles can call the function.
See who can call what
select
p.oid::regprocedure as function,
p.prosecdef as security_definer,
has_function_privilege('anon', p.oid, 'execute') as anon,
has_function_privilege('authenticated', p.oid, 'execute') as authenticated,
has_function_privilege('service_role', p.oid, 'execute') as service_role
from pg_proc p
where p.pronamespace = 'public'::regnamespace
order by 1;
The fix
grant execute on function public.your_function to authenticated;
If the function has arguments, name their types: public.your_function(uuid, text). Grant anon only when signed-out visitors must call it.
We ran the sequence in our test: a new function was callable by anon; after the two revokes anon got 42501; after grant execute ... to authenticated signed-in calls worked and anon stayed blocked.
A function is not covered by row level security
A security definer function runs with its owner's rights and can return rows the caller could not read from the table. Supabase lints 0028 and 0029 flag such functions when anon or authenticated can execute them. Tables the function reads still need their own grants and policies: use the tool below.
Write the fix for your tables
One table is free. The whole schema with a rollback file is $9 one-time.
Waiting for a paste.
Who can reach each table
Your tables show up here, one row each, with a choice of who can reach them.
Parsed in your browser. Your SQL is never uploaded, and no site or database is scanned.
Questions
Why do helper functions in my policies fail after hardening?
A policy that calls a function runs it as the calling role. If execute was revoked from that role, the policy fails. Supabase's guide says to grant execute on each new function to the roles that call it, including helper functions that policies call.
Why did revoking from anon change nothing?
Because the right comes through PUBLIC. Supabase's guide says to revoke from both public and the role you are restricting.
Sources
- PostgreSQL manual: CREATE FUNCTION, read 2026-11-10
- Supabase docs: Database Functions, read 2026-11-10
- splinter (Supabase Postgres linter): lint documentation, main branch, read 2026-11-10
- Our own test: the behaviour the reference pages describe, run against PGlite, read 2026-11-10
Related
- Every cause of 42501 on Supabase42501 means "insufficient privilege". Match your message to a row.
- All 30 Supabase advisor lintsName, level and one-line summary for every lint, 0001 to 0030.
- Grants for anon, authenticated and service_roleThree roles, four privileges. This is the grid the tool fills in.
- 42501, PGRST205, 42P01: which error is yours?Match the code in the response. See its HTTP status and whether a grant is the fix.