PostgreSQL Permissions for Public Schema After v15
Problem Statement
Since PostgreSQL 15, users often encounter permission denied for schema public errors when attempting to create tables as non-superusers. This occurs because:
- PostgreSQL 15+ revokes default
CREATEpermission on thepublicschema for non-owners - The change enhances security but breaks legacy workflows
- Privileges must be explicitly granted per-database
- Each database has its own isolated
publicschema
Security Change in v15
"PostgreSQL 15 revokes the
CREATEpermission from all users except a database owner from thepublic(or default) schema."
Core Solutions
1. Make Target User a Database Owner (Recommended)
The simplest solution is assigning ownership of your database to the application user:
-- When creating new databases:
CREATE DATABASE yourdb OWNER youruser;
-- For existing databases:
ALTER DATABASE yourdb OWNER TO youruser;Owners automatically receive full permissions on the public schema.
2. Explicitly Grant Permissions
If you can't change ownership, manually grant privileges in the target database:
# Connect to target database first
psql -d yourdbname -U postgres-- Grant privileges within target database
GRANT USAGE, CREATE ON SCHEMA public TO youruser;
-- Grant table privileges
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO youruser;WARNING
Privileges are database-specific. Executing grants without connecting to the target database does nothing!
Common Pitfalls & Fixes
Mistake: Granting Privileges in Wrong Database
# ERROR: Grants applied to wrong database
$ psql -c "GRANT CREATE ON SCHEMA public TO youruser;"
# FIX: Specify target database
$ psql -d yourdb -c "GRANT CREATE ON SCHEMA public TO youruser;"Mistake: Assigning ALL Instead of Ownership
-- Doesn't solve schema permissions
GRANT ALL ON DATABASE yourdb TO youruser;
-- Correct approach:
ALTER DATABASE yourdb OWNER TO youruser;Verifying Permissions
Check effective privileges with:
SELECT
has_schema_privilege('youruser', 'public', 'USAGE') AS has_usage,
has_schema_privilege('youruser', 'public', 'CREATE') AS has_create;Migration Workflow
Best Practices
Always create databases with owners
CREATE DATABASE appdb OWNER appuser;Avoid using the
postgresdatabase for applications
Create dedicated databases insteadConnect to target database before granting schema privileges
Limit superuser usage - Assign specific ownership instead
Why this changed?
This security enhancement prevents:
- Unauthorized object creation in public schema
- Privilege escalation risks
- Schema pollution by unprivileged users
Conclusion
PostgreSQL 15's permission changes require either:
- Assigning database ownership to application users
- Explicitly granting
USAGEandCREATEprivileges in the target database
Always verify permissions in the specific database where operations occur, as public schemas are database-specific. Proper permission management following these patterns ensures secure and functional PostgreSQL deployments in v15+.