Launch Offer: Use codelaunch30for 30% off

Error 42501: permission denied for table

This error occurs when Row Level Security (RLS) policies block access to a table. Learn how to fix it by creating proper RLS policies or using the service role key.

The 42501: permission denied error is one of the most common Supabase errors. It means your query was blocked by Row Level Security (RLS) policies.

Understanding the Error

When you see an error like:

permission denied for table users

Supabase is telling you that:

  1. The table has Row Level Security enabled
  2. No RLS policy allows your current operation
  3. The query was rejected to protect your data

This is actually a good thing - RLS is protecting your data from unauthorized access.

Why This Happens

RLS is Enabled but No Policies Exist

When you enable RLS on a table without creating any policies, all access is denied by default. This is secure by design.

SQL
-- This enables RLS but blocks everything
ALTER TABLE users ENABLE ROW LEVEL SECURITY;

-- Without policies, all queries fail with 42501
SELECT * FROM users; -- permission denied!

Policies Don't Match Your Use Case

You might have policies, but they don't cover your specific operation (SELECT, INSERT, UPDATE, DELETE) or your user's role.

Using the Wrong API Key

Supabase has two keys:

  • anon key - Subject to RLS policies (for client-side use)
  • service_role key - Bypasses RLS entirely (for server-side use only)

Using the anon key when you need elevated access causes this error.

How to Fix It

Solution 1: Create an RLS Policy

The proper fix is to create policies that define who can access what:

SQL
-- Allow users to read their own data
CREATE POLICY "Users can view own data"
ON users
FOR SELECT
USING (auth.uid() = id);

-- Allow users to update their own data
CREATE POLICY "Users can update own data"
ON users
FOR UPDATE
USING (auth.uid() = id);

Solution 2: Allow Public Read Access

For public data like blog posts or products:

SQL
-- Anyone can read published posts
CREATE POLICY "Public can view published posts"
ON posts
FOR SELECT
USING (published = true);

Solution 3: Use Service Role Key (Server-Side Only)

For admin operations or server-side code, use the service role key which bypasses RLS:

TYPESCRIPT
import { createClient } from '@supabase/supabase-js'

// Server-side only - never expose this key to the client!
const supabase = createClient(
  process.env.SUPABASE_URL,
  process.env.SUPABASE_SERVICE_ROLE_KEY
)

// This bypasses RLS
const { data } = await supabase.from('users').select('*')

Warning: Never use the service role key in client-side code. It bypasses all security.

Solution 4: Temporarily Disable RLS (Development Only)

For quick testing during development:

SQL
-- Disable RLS temporarily
ALTER TABLE users DISABLE ROW LEVEL SECURITY;

-- Don't forget to re-enable it!
ALTER TABLE users ENABLE ROW LEVEL SECURITY;

Warning: Never disable RLS in production.

Common RLS Policy Patterns

Authenticated Users Only

SQL
CREATE POLICY "Authenticated users can read"
ON posts
FOR SELECT
TO authenticated
USING (true);

Owner-Based Access

SQL
CREATE POLICY "Users can CRUD own records"
ON profiles
FOR ALL
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);

Role-Based Access

SQL
CREATE POLICY "Admins can do everything"
ON users
FOR ALL
TO authenticated
USING (
  EXISTS (
    SELECT 1 FROM profiles
    WHERE profiles.id = auth.uid()
    AND profiles.role = 'admin'
  )
);

Debugging Tips

  1. Check if RLS is enabled:

    SQL
    SELECT tablename, rowsecurity
    FROM pg_tables
    WHERE schemaname = 'public';
    
  2. List existing policies:

    SQL
    SELECT * FROM pg_policies
    WHERE tablename = 'your_table';
    
  3. Test as a specific user:

    SQL
    SET request.jwt.claims = '{"sub": "user-uuid-here"}';
    SELECT * FROM your_table;
    

Best Practices

  1. Always create policies when enabling RLS - Don't leave tables with RLS but no policies
  2. Use the principle of least privilege - Only grant the minimum access needed
  3. Test policies thoroughly - Check all CRUD operations for each user role
  4. Keep service role key secure - Only use server-side, never expose to clients

Related Errors

  • 42501 on functions - The function's SECURITY DEFINER setting may need adjustment
  • 42501 on sequences - Grant usage on sequences when allowing inserts