Skip to content

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 CREATE permission on the public schema for non-owners
  • The change enhances security but breaks legacy workflows
  • Privileges must be explicitly granted per-database
  • Each database has its own isolated public schema

Security Change in v15

"PostgreSQL 15 revokes the CREATE permission from all users except a database owner from the public (or default) schema."

Core Solutions

The simplest solution is assigning ownership of your database to the application user:

sql
-- 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:

sql
# Connect to target database first
psql -d yourdbname -U postgres
sql
-- 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

bash
# 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

sql
-- 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:

sql
SELECT 
  has_schema_privilege('youruser', 'public', 'USAGE') AS has_usage,
  has_schema_privilege('youruser', 'public', 'CREATE') AS has_create;

Migration Workflow

Best Practices

  1. Always create databases with owners
    CREATE DATABASE appdb OWNER appuser;

  2. Avoid using the postgres database for applications
    Create dedicated databases instead

  3. Connect to target database before granting schema privileges

  4. 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 USAGE and CREATE privileges 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+.