PG
PRO
42501ERRORTier 1 — Safe✅ HIGH confidence

permission denied for table

Category: Privilege Not GrantedVersions: All Postgres versions

What this means

The current role does not have the required privilege (SELECT, INSERT, UPDATE, DELETE, or TRUNCATE) on the named table or view. Postgres checks privileges at execution time against the pg_class and pg_namespace ACL entries.

Why it happens

  1. 1Role has not been granted SELECT or the required DML privilege on the table
  2. 2Role was granted privileges on an old version of the table but it was dropped and recreated (privileges do not transfer)
  3. 3Accessing a table through a view where the view's owner lacks the underlying table privilege
  4. 4Row-level security policy blocks access (raises a different message but same code in some cases)
  5. 5Schema-level USAGE privilege missing even if table-level SELECT is granted

How to reproduce

A role with no privileges attempts to query a table.

trigger — this will ERROR
CREATE ROLE readonly_user LOGIN PASSWORD 'pass';
CREATE TABLE private_data (secret TEXT);

-- As readonly_user:
SELECT * FROM private_data; -- triggers 42501
ERROR: permission denied for table private_data

Fix 1: Grant the required privilege to the role

When the role should legitimately have access.

fix
-- Grant SELECT on the specific table:
GRANT SELECT ON TABLE private_data TO readonly_user;

-- Grant USAGE on the schema too (required for table access):
GRANT USAGE ON SCHEMA public TO readonly_user;

-- For all future tables in the schema (Postgres 9.0+):
ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT ON TABLES TO readonly_user;

Why this works

Postgres evaluates table access by calling pg_class_aclcheck() which checks the ACL (access control list) stored in pg_class.relacl. GRANT adds an entry to this ACL. Schema USAGE is checked separately via pg_namespace.nspacl; both must pass for the query to proceed.

What not to do

Grant SUPERUSER to a role to work around permission errors

Why it's wrong: Superuser bypasses all permission checks including row security; use fine-grained GRANT instead.

Sources

📚 Official docs: https://www.postgresql.org/docs/current/errcodes-appendix.html

📚 Feature docs: https://www.postgresql.org/docs/current/sql-grant.html

🔧 Source ref: src/backend/catalog/aclchk.c — pg_class_aclcheck()

📖 Further reading: GRANT

📖 Further reading: Privileges

Confidence assessment

✅ HIGH confidence

Well-documented and stable. The ACL mechanism has been consistent across all supported versions. Edge case: when using row-level security, users with SELECT privilege may still see 42501 or receive empty results depending on the RLS policy definition.

See also

📄 Reference pages

GRANTPrivilegesRow Security
⚙️ This error reference was generated with AI assistance and reviewed for accuracy. Examples are provided to illustrate common scenarios and may not cover every case. Always test fixes in a development environment before applying to production. Spotted an error? Suggest a correction →