ERROR: permission denied for schema public
ID: database/pg-permission-denied-schema
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| 16 | active | — | — | — |
Root Cause
The current database role does not have the required privileges on the target schema. In PostgreSQL 15+, the default public schema no longer grants CREATE privilege to all users. This is a major breaking change that affects upgrades and new installations. Applications that previously created tables in the public schema as non-superuser roles will fail.
genericWorkarounds
-
95% success Grant specific schema privileges to the application role
As a superuser or schema owner, run: GRANT USAGE ON SCHEMA public TO app_role; GRANT CREATE ON SCHEMA public TO app_role; For PostgreSQL 15+ where public schema defaults changed: GRANT ALL ON SCHEMA public TO app_role; Also grant default privileges for future objects: ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_role;
-
90% success Create a dedicated schema for the application with proper ownership
CREATE SCHEMA app_schema AUTHORIZATION app_role; Then configure the application to use this schema: SET search_path TO app_schema, public; In connection strings, add ?options=-csearch_path%3Dapp_schema,public. The app_role has full control over schemas it owns.
Dead Ends
Common approaches that don't work:
-
Running the application as the postgres superuser to bypass permission checks
70% fail
Running applications as superuser violates the principle of least privilege and creates a security risk. Any SQL injection or application bug has full database access. This also masks permission issues that will resurface during security audits or role changes.
-
Granting ALL PRIVILEGES on all schemas to the application role
65% fail
Overly broad grants give the application role access to system schemas (pg_catalog, information_schema) and other application schemas. This creates security vulnerabilities and makes it harder to audit access. Grant only the specific privileges needed on specific schemas.