PostgreSQL "Permission Denied for Schema public" (15 and Later): Why GRANT ALL ON DATABASE Doesn't Fix It, and the Three Fixes That Do

Logeshwaran
—

"ERROR: permission denied for schema public" on CREATE TABLE means you're on PostgreSQL 15 or later, where ordinary users can no longer create objects in the public schema by default. The fix is one statement, run by the database's owner: GRANT CREATE ON SCHEMA public TO app;, with your application's user in place of app. Two other fixes work too: make the application's user the owner of the database, or give it a schema of its own. Here's what wastes most people's afternoon: the fix everyone tries first, GRANT ALL PRIVILEGES ON DATABASE, doesn't help at all, because database privileges don't include the schemas inside it. And if the wrong user runs the right GRANT, PostgreSQL prints "WARNING: no privileges were granted", then reports GRANT as if it worked. This page shows what changed in PostgreSQL 15, each fix with who can run it, the follow-up "permission denied for table" for other users, and the setup to use on Amazon RDS.

Ethan, a developer, gave the booking app for his friend Jake's phone repair shop a new PostgreSQL 17 database on Amazon RDS, with its own database user, as good practice says. The app's first migration failed on its first table. Ethan granted the user "all privileges" on the database. It failed again, with exactly the same message.

⚡ Quick Answer

• Fix: as the database owner, GRANT CREATE ON SCHEMA public TO app;. Details.

• Not the fix: GRANT ALL ON DATABASE. Why.

• "no privileges were granted": the wrong user ran the GRANT. Fix.

• Other users can't read the tables: grant SELECT and default privileges. How.

Can't connect at all? Our pg_hba.conf guide covers RDS SSL errors.

New to these terms? In PostgreSQL, a database holds schemas, which hold tables. Every new database has one schema, public, which is where tables go unless you say otherwise. Amazon RDS runs PostgreSQL for you, with the same rules.

🧭 NEW HERE? READ THESE FIRST

New to RDS and database permissions? These five pages make the rest of this one easy:

📌 Bookmark this; the fix table is the part you will come back for.

What changed in PostgreSQL 15

Here's Ethan's first migration, as the app's user on PostgreSQL 17:

CREATE TABLE repairs (id serial PRIMARY KEY, device text);
ERROR:  permission denied for schema public
LINE 1: CREATE TABLE repairs (id serial PRIMARY KEY, device text);
                     ^

The same statement, by the same kind of user, works on PostgreSQL 14. Until version 14, every user could create objects in public. Starting with PostgreSQL 15, that right was removed, and the public schema now belongs to a special role, pg_database_owner, which means "whoever owns this database":

PostgreSQL 14PostgreSQL 15 and later
Owner of the public schemapostgrespg_database_owner
New user runs CREATE TABLEWorkspermission denied for schema public
Everyone can still use objects in publicYesYes, but not create them

The change closes a security hole: on shared databases, any user could create objects that other users' queries might pick up by accident. The cost lands on you: every application user you create now needs to be given somewhere to create its tables, on purpose.

Jake: "So the database stopped letting strangers put things in the lobby?"

Ethan: "And our app is a stranger until someone hands it a key. I'd been handing it keys to the wrong door."

Why GRANT ALL ON DATABASE doesn't fix it

The first thing almost everyone tries:

GRANT ALL PRIVILEGES ON DATABASE shopapp TO app;

It runs without complaint, and the next CREATE TABLE fails exactly as before. Privileges on a database cover only database-level actions: connecting, creating new schemas, and creating temporary tables. They say nothing about the schemas inside it. Creating a table in public needs the CREATE privilege on the schema, which is a separate grant.

When you hit this error, work through it in order:

  1. Check your server version with SHOW server_version;. On 15 or later, this behavior is expected.
  2. Connect to the database your app uses, not the default postgres database.
  3. Check whether your app's user can create there: SELECT has_schema_privilege('app', 'public', 'CREATE'); returns f when it can't.
  4. Find the database's owner with the query in the next section, and connect as that user.
  5. Apply one of the three fixes below, then run the has_schema_privilege check again; it should say t.

Fix 1: grant CREATE on the public schema

Connected to the right database, as its owner, grant the schema privilege:

GRANT CREATE ON SCHEMA public TO app;

Then your app's CREATE TABLE works. Two details matter. You must be connected to the database in question, because each database has its own public schema; in psql, that's \c shopapp first. And you must run the GRANT as the database's owner, or as a superuser. On Amazon RDS, the master user isn't a real superuser, but if it created the database, it owns it, so it can run this grant.

"WARNING: no privileges were granted": the GRANT that does nothing

Run the same GRANT as a user who doesn't own the database, and PostgreSQL answers like this:

WARNING:  no privileges were granted for "public"
GRANT

The command finishes with GRANT, the same word a successful grant prints, so if your script only checks for errors, it treats this as success. Nothing changed. Check who owns the schema and the database:

SELECT nspname, pg_get_userbyid(nspowner) FROM pg_namespace WHERE nspname = 'public';
SELECT datname, pg_get_userbyid(datdba) FROM pg_database WHERE datname = current_database();

On PostgreSQL 15 and later, the first query shows pg_database_owner, and the second tells you which user that is for your database. Connect as that user and run your GRANT again.

Jake: "It said GRANT, but it didn't grant anything?"

Ethan: "It said it in small print, in a warning above. The word GRANT just means the command finished."

Fix 2: make the application's user the database owner

If your database exists only for one application, the simplest arrangement is to make your application's user its owner. The owner is pg_database_owner for that database, so it can create in public without any grant:

ALTER DATABASE shopapp OWNER TO app;

A superuser can run that as it is. A user who isn't a superuser, such as the master user on Amazon RDS, meets one more rule on PostgreSQL 16 and later: it must be able to act as the new owner, or the command fails:

ERROR:  must be able to SET ROLE "app"

Grant yourself membership in the app's role first; a user that can create roles can do that for roles it created. Then create the database with the right owner from the start, which is the cleanest version:

GRANT app TO CURRENT_USER;
CREATE DATABASE shopapp OWNER app;

The trade-off: the application's user now owns everything in the database, including the right to drop it, so this fits single-application databases better than shared ones.

Fix 3: give the application a schema of its own

If you share one database between several applications, the tidiest fix is a schema named after your application's user, owned by it:

CREATE SCHEMA app AUTHORIZATION app;

You don't need to change your application. PostgreSQL's default search path is "$user", public: it looks for a schema with the user's own name first. So the app's unchanged CREATE TABLE repairs now lands in the app schema:

 schemaname | tablename
------------+-----------
 app        | repairs
(1 row)

Each application gets its own space, and nobody needs CREATE on public. Here's how the three fixes compare:

FixRun byBest for
GRANT CREATE ON SCHEMA public TO appDatabase ownerQuick fix; existing apps that expect public
ALTER DATABASE ... OWNER TO appCurrent owner or superuserOne database per application
CREATE SCHEMA app AUTHORIZATION appDatabase ownerSeveral applications in one database

The next error: other users and "permission denied for table"

Once the app creates its tables, a second user, such as a reporting account, hits the next wall:

ERROR:  permission denied for table repairs

Tables belong to the user who created them, and other users need explicit grants. As the app's user, grant read access to everything that exists, and set default privileges so tables created later are covered too:

GRANT SELECT ON ALL TABLES IN SCHEMA public TO reporter;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO reporter;

Without the second line, the reporting user can read today's tables and gets "permission denied" again on the first table the app adds next month. Default privileges apply to tables created by the user who ran the ALTER DEFAULT PRIVILEGES, which is why the app's own user should run it.

Setting up an application database on RDS

On Amazon RDS for PostgreSQL 15 and later, this is the order that avoids every error on this page:

  1. Connect as the master user and create the application's user: CREATE ROLE app LOGIN PASSWORD '...';.
  2. Give the master user membership in that role with GRANT app TO CURRENT_USER;, then create the database owned by it: CREATE DATABASE shopapp OWNER app;. Or, for a shared database, create it as the master user and run CREATE SCHEMA app AUTHORIZATION app; inside it.
  3. Create any read-only users, and have the app's user grant them SELECT plus default privileges.
  4. Store each user's password in Secrets Manager, not in the application's code.
  5. Run the app's migrations once by hand and read the output for any WARNING lines, not just errors.

Migration tools in every framework run plain CREATE TABLE statements as the app's user, so the same fixes apply whatever you use. If the app can't reach the database at all, our RDS connection guide covers the network side.

Troubleshooting by symptom

ERROR: permission denied for schema public

PostgreSQL 15 or later. As the database owner, run GRANT CREATE ON SCHEMA public TO your app's user.

GRANT ALL ON DATABASE didn't help

Database privileges don't cover schemas. Grant CREATE on the schema instead.

WARNING: no privileges were granted for "public"

You're not the database owner. Find the owner with pg_database, connect as that user, and grant again.

The GRANT worked, but CREATE TABLE still fails

You granted in a different database. Connect to the app's database first; each has its own public schema.

ERROR: must be able to SET ROLE

On PostgreSQL 16 and later, a non-superuser must be a member of the new owner's role. Run GRANT app TO CURRENT_USER first.

ERROR: permission denied for table

Another user created the table. Have that user grant SELECT, plus ALTER DEFAULT PRIVILEGES for future tables.

It worked on PostgreSQL 14 but not after upgrading

Databases upgraded from 14 keep their old public schema settings; new ones on 15 and later don't. Grant explicitly.

PostgreSQL permission denied for schema public: frequently asked questions

What does permission denied for schema public mean?

Your user can't create objects in the public schema. On PostgreSQL 15 and later, that's the default for every user except the database owner.

How do I fix permission denied for schema public in PostgreSQL 15?

As the database owner, run GRANT CREATE ON SCHEMA public TO your user, connected to that database.

Why doesn't GRANT ALL PRIVILEGES ON DATABASE fix it?

Database privileges cover connecting, creating schemas and temporary tables, not creating tables in a schema.

Who owns the public schema in PostgreSQL 15?

The pg_database_owner role, which stands for whoever owns the database.

Does this happen on Amazon RDS for PostgreSQL?

Yes, on version 15 and later, the same as standard PostgreSQL.

Can the RDS master user grant CREATE on schema public?

Yes, for databases it owns, such as ones it created. For others, connect as the owner.

What does WARNING no privileges were granted mean?

The user running GRANT isn't allowed to grant that privilege, so nothing changed, even though GRANT is printed.

How do I make a user the owner of a PostgreSQL database?

Run CREATE DATABASE name OWNER user, or ALTER DATABASE name OWNER TO user. Non-superusers on PostgreSQL 16+ need membership in that role first.

What is the search_path in PostgreSQL?

The list of schemas PostgreSQL searches for unqualified names. The default is "$user", public.

How do I give an application its own schema?

Run CREATE SCHEMA name AUTHORIZATION user with the user's own name; its tables then go there by default.

How do I give a read-only user access to all tables?

GRANT SELECT ON ALL TABLES IN SCHEMA public, plus ALTER DEFAULT PRIVILEGES ... GRANT SELECT ON TABLES for new ones.

Why can't my reporting user see new tables?

GRANT SELECT ON ALL TABLES covers only existing tables. Default privileges cover the ones created later.

Should I just grant CREATE on public to PUBLIC again?

It restores the old behavior, and the old security risk. Grant it to the specific users that need it instead.

Do upgraded databases have this problem?

Databases upgraded from PostgreSQL 14 keep their old public schema permissions; databases created on 15 and later don't.

Does this affect Django, Rails or Prisma migrations?

Yes. Their migrations run CREATE TABLE as the app's user, so grant CREATE on the schema or use an owned schema.

Is this the same as permission denied for table?

No. That error is about privileges on an existing table, granted separately by the table's owner.

For readers preparing for an AWS certification

We have been covering AWS certifications alongside our fixes, so here is a short extra for readers studying for one. If you only came for the fix, you already have it; feel free to skip this part.

Exams that test this topic: Developer – Associate (DVA-C03 from December 1, 2026) • CloudOps Engineer – Associate (SOA-C03).

Here are the exam-style questions this topic tends to raise, with the reasoning you need to answer them:

1. Why does a new PostgreSQL 15 user get "permission denied for schema public"?

PostgreSQL 15 removed the default CREATE privilege on the public schema for all users.

2. How do you allow an application user to create tables?

Grant CREATE on the schema, or better, create a dedicated schema owned by that user.

3. Which role do RDS master users belong to?

rds_superuser, which has broad but not full superuser rights.

4. How do you give a read-only user access to future tables?

ALTER DEFAULT PRIVILEGES to grant SELECT on tables created later.

5. Does upgrading an older database change existing grants?

No. The new default applies to newly created databases; upgraded ones keep their grants.

6. How do you see a user's privileges?

With psql meta-commands such as \dn+ and \dp, or the information_schema views.

Exam codes and dates change often. Our AWS certification changes page keeps track of what is current.

Ethan dropped the half-created database, gave his master user membership in the app's role, and made the database again with CREATE DATABASE shopapp OWNER app;. The migration ran clean, and the reporting user got SELECT plus default privileges in the same session. Jake asked why the "all privileges" grant hadn't worked. "All the privileges of the building," Ethan said, "none of the rooms."

📌 If you keep one line from this page

On PostgreSQL 15 and later, grant CREATE on the schema, not the database, as the database's owner, or make the app's user the owner, and watch for "no privileges were granted".

GRANT CREATE ON SCHEMA public · CREATE DATABASE ... OWNER app · CREATE SCHEMA app AUTHORIZATION app · ALTER DEFAULT PRIVILEGES.

Revision note. Written October 13, 2026, for PostgreSQL 15 to 18, including Amazon RDS for PostgreSQL. "Good fences make good neighbors," goes the old saying; PostgreSQL 15 built the fence, and every app now needs a gate of its own.

Related