ERROR: permission denied for schema public on a CREATE TABLE
means your role may connect and read, but not create objects in public.
Since PostgreSQL 15 only the database owner can, so grant
CREATE ON SCHEMA public to the role or make it the database owner.
The quickest fix is one statement run as the owner or a superuser:
GRANT CREATE ON SCHEMA public TO maria. For an application database, making
the application role the owner of the whole database is usually cleaner.
The error
docker exec fix4-pg18 psql -U maria -d appdb -v VERBOSITY=verbose -c "CREATE TABLE t(id int)"
ERROR: 42501: permission denied for schema public
LINE 1: CREATE TABLE t(id int)
^
LOCATION: aclcheck_error, aclchk.c:2793
Why it happens
PostgreSQL 15 changed the default privileges of the public schema. Before it,
every role (the pseudo-role PUBLIC) could create tables there. From 15 on the
schema belongs to pg_database_owner, a role that always means "whoever owns
this database", and everyone else only gets USAGE. This is what a fresh
PostgreSQL 18 database shows:
docker exec fix4-pg18 psql -U postgres -d postgres -c "\dn+ public"
Name | Owner | Access privileges | Description
--------+-------------------+----------------------------------------+------------------------
public | pg_database_owner | pg_database_owner=UC/pg_database_owner+| standard public schema
| | =U/pg_database_owner |
UC is usage and create for the owner; =U is usage only for
everyone else. So a role that is neither the owner nor a superuser can select from
tables it was granted, but its first migration fails with code 42501, "insufficient
privilege". Tutorials written for PostgreSQL 14 and older skip this step because it was
not needed then, which is why the error shows up after an upgrade or a new container.
The fix
docker exec fix4-pg18 psql -U postgres -d appdb -c "GRANT CREATE ON SCHEMA public TO maria"
GRANT
docker exec fix4-pg18 psql -U maria -d appdb -v VERBOSITY=verbose -c "CREATE TABLE t(id int)"
CREATE TABLE
The grant has to run inside the database that owns the schema (-d appdb),
because each database has its own public. fix4-pg18,
appdb and maria are the test's own names. The alternative is
ownership: on a second database on the same server,
ALTER DATABASE appdb2 OWNER TO david let the role david create a
table with no grant at all, because the owner of the database is
pg_database_owner for its public schema. That suits an
application role that runs its own EF Core migrations; the grant suits a second role
that only needs to add tables next to someone else's.
How it was reproduced
A fresh postgres:18 container (PostgreSQL 18.4, Debian build) on Docker
Desktop 4.91.0 under Windows 11. The superuser created the database appdb,
so postgres owned it, and a login role maria with no other
privileges. Connected as maria, CREATE TABLE failed as shown;
after the grant the same command succeeded, and \dt listed the table as owned
by maria.
Frequently asked
- Why do I get permission denied for schema public in PostgreSQL 15?
- PostgreSQL 15 removed the CREATE privilege on the public schema from PUBLIC. Only the database owner and superusers can create objects there unless you grant CREATE ON SCHEMA public to a role.
- How do I grant CREATE on schema public?
- Connect to the database in question as its owner or a superuser and run GRANT CREATE ON SCHEMA public TO rolename. Each database has its own public schema, so the grant applies to that database only.
- Should my application role own the database?
- For a database that belongs to one application and is migrated by it, yes: ALTER DATABASE name OWNER TO approle gives it create rights on public without extra grants. Shared databases are better served by explicit grants.
More decoded errors in the Fixes category. For how databases, schemas and roles fit together if you come from SQL Server, see databases, schemas and roles in PostgreSQL.