This error occurs when attempting to grant role privileges or permissions using a user account that lacks the necessary ADMIN OPTION on the role being granted, or when using GRANTED BY with insufficient privileges.
The PostgreSQL error code 0L000 with the message "invalid_grantor" indicates that the user or role attempting to grant privileges does not have the proper authorization to act as a grantor for that specific grant operation. In PostgreSQL's privilege system, not every user can grant every privilege. To grant a role to another user, you must either be a superuser, own the object being granted, or possess the ADMIN OPTION on that role. The grantor is the entity recorded in the system catalogs as having made the grant, and PostgreSQL enforces strict rules about who can be a valid grantor. This error most commonly appears when using the GRANT command with the GRANTED BY clause, or when a user tries to grant privileges they don't actually have the authority to delegate. PostgreSQL versions 16.9 had a specific bug related to this validation that was fixed in 16.10.
Check what roles and privileges your current user has:
-- Check current user
SELECT current_user;
-- View all role memberships and admin options
SELECT
r.rolname as role_name,
m.rolname as member_of,
a.admin_option
FROM pg_roles r
JOIN pg_auth_members a ON r.oid = a.member
JOIN pg_roles m ON a.roleid = m.oid
WHERE r.rolname = current_user;
-- Check if you have admin option on the target role
SELECT
grantor.rolname AS grantor_name,
member.rolname AS member_name,
admin_option
FROM pg_auth_members am
JOIN pg_roles grantor ON am.grantor = grantor.oid
JOIN pg_roles member ON am.member = member.oid
WHERE member.rolname = current_user;This helps identify whether you have the necessary ADMIN OPTION to grant the role.
If you're using the GRANTED BY clause, try removing it:
-- Instead of this (which may fail):
GRANT role_name TO user_name GRANTED BY specific_user WITH ADMIN OPTION;
-- Try this:
GRANT role_name TO user_name WITH ADMIN OPTION;The GRANTED BY clause is optional and often unnecessary. By default, PostgreSQL uses the current user as the grantor, which is usually what you want.
Connect as a superuser or the role owner and perform the grant:
-- Connect as postgres superuser
-- psql -U postgres -d your_database
-- Grant the role with admin option
GRANT role_name TO target_user WITH ADMIN OPTION;Superusers bypass all permission checks and can always act as valid grantors.
If you need a non-superuser to be able to grant roles, first grant them ADMIN OPTION:
-- As superuser, grant ADMIN OPTION to the user who needs to grant roles
GRANT role_name TO intermediate_user WITH ADMIN OPTION;
-- Now intermediate_user can grant role_name to others
-- (connect as intermediate_user)
GRANT role_name TO final_user;This creates a proper chain of authority for role grants.
PostgreSQL 16.9 has a known bug that causes incorrect "invalid_grantor" errors when combining GRANTED BY with WITH ADMIN OPTION. Upgrade to 16.10 or later:
# Check current version
psql --version
# For Ubuntu/Debian
sudo apt update
sudo apt upgrade postgresql
# For RHEL/CentOS
sudo yum update postgresql-server
# For Docker
docker pull postgres:16.10
# or
docker pull postgres:17The bug was fixed in PostgreSQL 16.10, and upgrading resolves the validation logic issue.
Check the pg_auth_members system catalog to understand existing grant relationships:
-- View all role grants and their grantors
SELECT
grantor.rolname AS granted_by,
role.rolname AS role_granted,
member.rolname AS granted_to,
admin_option
FROM pg_auth_members am
JOIN pg_roles grantor ON am.grantor = grantor.oid
JOIN pg_roles role ON am.roleid = role.oid
JOIN pg_roles member ON am.member = member.oid
ORDER BY role.rolname, member.rolname;This helps identify the complete chain of grants and where the invalid_grantor issue originates.
Understanding the Grantor Concept
In PostgreSQL's security model, every grant operation is recorded with a "grantor" - the role responsible for making the grant. This matters because if a grantor's privileges are later revoked, all dependent grants must also be revoked (a cascading effect).
GRANTED BY Clause Semantics
The GRANTED BY clause allows you to explicitly specify who should be recorded as the grantor. However, you can only specify another role as the grantor if:
1. You are a superuser, OR
2. You currently possess all the privileges of that other role (via role membership with ADMIN OPTION)
This prevents privilege escalation where a user could falsely attribute grants to someone else.
The PostgreSQL 16.9 Bug
PostgreSQL 16.9 introduced stricter validation logic that was overly aggressive. The bug caused legitimate GRANT operations to fail when using GRANTED BY with WITH ADMIN OPTION, even when the grantor had proper privileges. This was fixed in 16.10 by adjusting the validation to correctly handle the ADMIN OPTION inheritance rules.
Bootstrap Superuser Exception
The "bootstrap superuser" (typically the postgres user created during database initialization) has special status and is exempt from grantor validation checks. Grants made by the bootstrap superuser never become invalid due to privilege revocation.
Role Self-Granting Limitation
A critical but often overlooked rule: a role is NOT considered to hold WITH ADMIN OPTION on itself. This means you cannot use GRANTED BY to attribute a grant to a role when granting that same role to someone else, even if you're logged in as that role.
Cascading Revocations
When ADMIN OPTION is revoked from a grantor, PostgreSQL automatically revokes all dependent grants that the grantor made. This can have far-reaching effects in complex role hierarchies, so be cautious when revoking ADMIN OPTION 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