ERROR: must be owner of table patient (SQLSTATE 42501) means the role can read
and write the table but does not own it, and ALTER TABLE needs the owner. Run
the change as the owner, or make the role the owner with
ALTER TABLE patient OWNER TO clinic_app.
In the test, clinic_app had SELECT, INSERT, UPDATE, DELETE on the
table and its INSERT worked, yet ALTER TABLE ... ADD COLUMN failed
until ownership moved. GRANT did not cover the schema change; ownership did.
The error
SET ROLE clinic_app;
SET
INSERT INTO patient VALUES (1, 'Maria Garcia');
INSERT 0 1
ALTER TABLE patient ADD COLUMN phone text;
psql:/tmp/f42501.sql:7: ERROR: 42501: must be owner of table patient
LOCATION: aclcheck_error, aclchk.c:2931
Why it happens
The table was created by postgres, so postgres owned it, as
\dt showed:
List of tables
Schema | Name | Type | Owner
--------+---------+-------+----------
public | patient | table | postgres
(1 row)
The four table privileges granted to clinic_app covered the data, and the
insert went through. The ALTER TABLE was refused with 42501 and the message
names the missing thing directly: ownership of patient. A follow-up test with
GRANT ALL ON invoice TO clinic_app on a second table ended the same way:
must be owner of table invoice. The setup to look for is one role that created
the tables and another that now runs the schema change.
The fix
ALTER TABLE patient OWNER TO clinic_app;
ALTER TABLE
SET ROLE clinic_app;
SET
ALTER TABLE patient ADD COLUMN phone text;
ALTER TABLE
SELECT * FROM patient;
id | full_name | phone
----+--------------+-------
1 | Maria Garcia |
(1 row)
RESET ROLE;
RESET
List of tables
Schema | Name | Type | Owner
--------+---------+-------+------------
public | patient | table | clinic_app
(1 row)
The first statement ran as postgres, the current owner. After it,
clinic_app added the column and \dt lists it as the owner. Pick the
role that runs your migrations as the owner of the tables they change; the role that only
reads and writes data can keep plain grants. The other way out, without moving ownership,
is to run the ALTER TABLE itself as the owning role, as the first line here
ran as postgres.
How it was reproduced
A postgres:18 container (PostgreSQL 18.4, Debian 18.4-1.pgdg13+1) on Docker
Engine 29.9.2, database lab. The script f42501.sql, run as
postgres with
docker exec fix8-pg3 sh -c "psql -U postgres -d lab -e -f /tmp/f42501.sql 2>&1",
created a login role clinic_app and a table patient, granted the
four data privileges, switched with SET ROLE clinic_app, inserted a fictional
row and tried the ALTER TABLE. \set VERBOSITY verbose at the top
adds the SQLSTATE. The container and role names are the test's own.
Frequently asked
- Why can my PostgreSQL user insert but not ALTER TABLE?
- INSERT needs a privilege that GRANT gives; ALTER TABLE needed ownership in the test. clinic_app inserted a row and then got must be owner of table patient on ADD COLUMN.
- How do I change the owner of a table in PostgreSQL?
- Run ALTER TABLE patient OWNER TO clinic_app as the current owner; in the test that was postgres. Then \dt listed clinic_app as the owner and the ADD COLUMN worked.
- Does GRANT ALL fix 'must be owner of table'?
- No, not in the test. After GRANT ALL ON invoice TO clinic_app, ALTER TABLE invoice ADD COLUMN paid boolean still failed with must be owner of table invoice. Moving ownership fixed the patient table.
More decoded errors in the Fixes category. The same code with a different message, for creating tables, is in PostgreSQL: permission denied for schema public.