Skip to content

Supabase database errorSupabase: “permission denied for schema auth”

You created your own Postgres role, for a worker, a reporting tool or an AI agent, and it fails with ERROR: 42501: permission denied for schema auth as soon as a policy or function calls auth.uid(). You ran grant usage on schema auth to the role, the SQL editor said success, and nothing changed. On hosted Supabase that grant can’t work. Here is why, in Supabase’s words, and the three ways to give the role what it needs, or hand it over at a fixed price.

Short answer

The postgres role holds usage on the auth schema without the grant option, so its grant to your role is quietly ignored. Read the user ID through a small security definer function in a private schema, read it from the JWT claims, or make the role a member of authenticated if it should have everything signed-in users have. Then grant the role your tables, with RLS policies written for it.

Why the grant is ignored, and the fixes that work

  1. 01

    The grant looks like it worked

    “On hosted Supabase, that grant has no effect.” Supabase, Permission errors when granting custom roles access to the auth schema

    Postgres only logs WARNING: no privileges were granted for "auth", and the SQL editor shows success. A grant of select on auth.users also succeeds, but the role still can’t reach the table without usage on the schema. grant execute on function auth.uid() changes nothing either, because every role already has it.

  2. 02

    postgres can’t pass on a privilege it can’t grant

    “In Postgres, a role can grant a privilege only if it holds the privilege with the grant option.” Supabase, Permission errors when granting custom roles access to the auth schema

    supabase_admin owns the auth schema and supabase_auth_admin owns the tables and functions in it. postgres isn’t a superuser and can’t become either: grant supabase_auth_admin to postgres fails with "supabase_auth_admin" role memberships are reserved, only superusers can grant them, and set role supabase_auth_admin is denied. Remove the grant usage on schema auth lines from your migrations.

  3. 03

    Check what the role can reach

    Run this in the SQL editor with your role’s name. can_execute_uid comes back true for every role. If auth_schema_usage is false, the role can’t reach anything in auth and auth.uid() fails, so use one of the three fixes below.

    select
      has_schema_privilege('my_role', 'auth', 'usage') as auth_schema_usage,
      has_function_privilege('my_role', 'auth.uid()', 'execute') as can_execute_uid;
  4. 04

    Fix 1: read the user ID through a security definer function

    “Keep it in a schema that isn't exposed through the Data API.” Supabase, Permission errors when granting custom roles access to the auth schema

    The function runs as postgres, which can call auth.uid(), so your role only needs execute on it. Create it as postgres in a private schema, pin search_path and return only what the caller needs. This is Supabase’s example:

    create schema if not exists private;
    
    create or replace function private.current_user_id()
    returns uuid
    language sql
    security definer
    set search_path = ''
    stable as $$
      select auth.uid();
    $$;
    
    revoke all on function private.current_user_id() from public;
    grant usage on schema private to my_role;
    grant execute on function private.current_user_id() to my_role;
  5. 05

    Fix 2: read the user ID from the JWT claims

    “auth.jwt() fails for a custom role in the same way as auth.uid().” Supabase, Permission errors when granting custom roles access to the auth schema

    auth.uid() reads the user ID from request settings the Data API sets from the user’s JWT. auth.jwt() fails for a custom role the same way, but your own function can read those settings with no access to auth and without security definer. Read another claim, such as role, with ->> 'role' on the same claims:

    create schema if not exists private;
    
    create or replace function private.request_user_id()
    returns uuid
    language sql
    stable
    set search_path = ''
    as $$
      select coalesce(
        nullif(current_setting('request.jwt.claim.sub', true), ''),
        (nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'sub')
      )::uuid
    $$;
    
    grant usage on schema private to my_role;
    grant execute on function private.request_user_id() to my_role;
  6. 06

    Fix 3: make the role a member of authenticated

    “Grant this membership only if the role needs all of that access.” Supabase, Permission errors when granting custom roles access to the auth schema

    grant authenticated to my_role gives the role usage on auth and every privilege signed-in users have, including your tables in public. A membership granted with inherit false doesn’t give usage on auth.

    grant authenticated to my_role;
  7. 07

    Point policies and foreign keys at your own tables

    “A foreign key to auth.users needs access to the auth schema, so a table that a custom role owns can't have one.” Supabase, Permission errors when granting custom roles access to the auth schema

    With fix 1 or 2, the role still needs a grant on each table it uses and RLS policies written for it, such as to my_role using ( owner_id = (select private.current_user_id()) ). For a foreign key to the user, create your own profile table in a schema you control and reference it instead of auth.users. Then test as the role itself: the SQL editor runs as postgres and skips RLS.

Checked against the vendor’s docs on : Supabase troubleshooting: Permission errors when granting custom roles access to the auth schema; Supabase docs: Database roles; PostgreSQL docs: GRANT (the grant option).

Rather hand it over?

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

Related: Supabase “permission denied to change default privileges” · Supabase infinite recursion in RLS policy · Supabase select returns an empty array · Supabase AuthRetryableFetchError

Questions

More on this error

Why does auth.uid() work for signed-in users but not for my role?

The authenticated role has usage on the auth schema and your role doesn’t. Every role can execute auth.uid(), but a function in a schema the role can’t use still fails with permission denied for schema auth.

Can I give my role access to auth.users directly?

Not on hosted Supabase, because postgres can’t grant usage on the auth schema. Read only what the role needs through a small security definer function, such as whether a user has a session, and restrict execute on it to your role.

Can you fix it for me?

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

A different error?

Describe it and get a written quote

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.