The "Must be owner of table" error occurs when a user attempts to alter, drop, or modify a table they do not own. Only the table owner (or superuser) can perform schema modifications on a table in PostgreSQL.
PostgreSQL enforces strict ownership rules on database objects. When you attempt to ALTER, DROP, or modify a table using DDL (Data Definition Language) statements, PostgreSQL checks if the current user owns that table. If you don't own it, the operation fails with the "Must be owner of table" error. This is fundamentally different from permission-based access control. Even if you have SELECT, INSERT, UPDATE, and DELETE privileges on a table (which are grantable), you cannot alter its schema, add constraints, add columns, or drop it unless you are the owner or a superuser. Table ownership is inherent to the creator and cannot be delegated through GRANT statements. This restriction is a security feature that prevents unauthorized schema modifications and maintains data integrity by ensuring only authorized users can change table structure.
First, identify the current table owner by querying the PostgreSQL system catalogs:
SELECT t.table_name, t.table_schema, u.usename as owner
FROM information_schema.tables t
JOIN pg_catalog.pg_class c ON (t.table_name = c.relname)
JOIN pg_catalog.pg_user u ON (c.relowner = u.usesysid)
WHERE t.table_schema = 'public' AND t.table_name = 'your_table_name';Or for a specific table:
SELECT tableowner FROM pg_tables WHERE tablename = 'your_table_name';Compare the owner column with your current user (check via SELECT CURRENT_USER;).
If you have superuser privileges, transfer ownership to the user who needs to manage the table:
ALTER TABLE public.your_table_name OWNER TO current_user;Or explicitly specify the username:
ALTER TABLE public.your_table_name OWNER TO application_user;After this, the new owner can perform all DDL operations on that table.
If running database migrations (Liquibase, Alembic, Prisma migrate), ensure the migration runner uses the correct database role:
# PostgreSQL connection string with explicit user
DATABASE_URL="postgresql://app_user:password@localhost:5432/mydb"
npx prisma migrate deployThe user in the connection string must be the owner of the tables being migrated. Create a role that owns all application tables:
CREATE ROLE app_owner;
ALTER ROLE app_owner LOGIN PASSWORD 'secure_password';
ALTER ROLE app_owner CREATEDB;
-- When creating tables, connect as app_owner
ALTER TABLE existing_table OWNER TO app_owner;In production environments, PostgreSQL best practice is to use role membership instead of giving direct table ownership to individual users:
-- Create a group role that owns all application tables
CREATE ROLE app_group NOLOGIN;
-- Grant membership to individual users
GRANT app_group TO app_user;
GRANT app_group TO app_admin;
-- All tables owned by app_group
CREATE TABLE schema.table_name (...) [with app_group as owner];Users in the app_group role can then:
- ALTER, DROP, and modify tables (via role membership)
- Still authenticate with individual credentials
- Be added/removed from the group without changing table ownership
To set the role during DDL operations:
SET ROLE app_group;
ALTER TABLE table_name ADD COLUMN new_col INTEGER;In development environments only, you can temporarily grant superuser privileges to perform schema changes:
-- As superuser (postgres), temporarily enable superuser on application user
ALTER ROLE app_user SUPERUSER;
-- Run your migrations/DDL
-- Then revoke superuser
ALTER ROLE app_user NOSUPERUSER;Do NOT use this in production. Superuser bypasses all security checks and should only be used by database administrators.
If you only need to CREATE new tables (not modify existing ones), grant schema privileges instead:
GRANT USAGE ON SCHEMA public TO app_user;
GRANT CREATE ON SCHEMA public TO app_user;This allows the user to create new tables (which they will own), but they still cannot modify tables owned by other users. For modifying existing tables, only ownership or superuser status helps.
Role Membership and Ownership: A PostgreSQL role can be a group role (NOLOGIN) or a user role (LOGIN). When you CREATE TABLE as a group role member using SET ROLE, the table is owned by the group, not the individual user. This is the recommended production pattern.
Superuser Override: Superusers bypass object ownership checks entirely. Only superusers can change ownership of objects with ALTER ... OWNER TO. However, granting superuser to application accounts violates principle of least privilege.
Default Privileges: For new tables created after a role change, use ALTER DEFAULT PRIVILEGES to control future ownership:
ALTER DEFAULT PRIVILEGES IN SCHEMA public OWNER TO app_group GRANT SELECT ON TABLES TO readonly_group;Schema vs. Table Ownership: Confusing schema permissions with table ownership is common. You can have CREATE on a schema but still not own existing tables in it. Use GRANT CREATE ON SCHEMA for schema-level permissions and ALTER TABLE OWNER TO for individual table ownership.
Cloud Databases: Managed services (AWS RDS, Azure Database, Google Cloud SQL) often restrict superuser privileges. You must use role membership and ALTER TABLE OWNER TO commands instead. Some services provide restricted superuser equivalents with fewer privileges.
ERROR: syntax error at end of input
Syntax error at end of input in PostgreSQL
Bind message supplies N parameters but prepared statement requires M
Bind message supplies N parameters but prepared statement requires M in PostgreSQL
Multidimensional arrays must have sub-arrays with matching dimensions
Multidimensional arrays must have sub-arrays with matching dimensions
ERROR: value too long for type character varying
Value too long for type character varying
insufficient columns in unique constraint for partition key
How to fix "insufficient columns in unique constraint for partition key" in PostgreSQL