TECH BLOG
技術ブログ
  • 2025-04-20 PostgreSQLPostgreSQL ナレッジPostgreSQL バージョンアップ

    GRANT文の実行時に発生する”ERROR: permission denied to grant privileges as role <ロール名>“エラー

ロールを付与する GRANT 文がエラーとなる

ロールを付与する GRANT 文の挙動を確認していますと、同じ GRANT 文を実行した際に、"ERROR: permission denied to grant privileges as role <ロール名>" が発生するバージョンと、発生しないバージョンがあることに気がつきました。

PostgreSQL 15 以降でエラーとなる GRANT 文

実際にエラーとなる GRANT 文は下記のようなものです。

GRANT ippan_role_a TO ippan_role_b;

ippan_role_a ロールを ippan_role_b ロールに付与する GRANT 文となります。
これを ippan_role_a ロールで実行すると、PostgreSQL 15 以降ではエラーとなります。
PostgreSQL 16.6 で出力されるエラーメッセージを下記に記載します。

ERROR: must have admin option on role "role_ippan_a"
DETAIL: Only roles with the ADMIN option on role "role_ippan_a" may grant this role.

「role_ippan_a に対する ADMIN OPTION が必要」というエラーメッセージです。
なお、エラーとなるのは PostgreSQL 15 以降のバージョンです。
PostgreSQL 14 以前では問題なく完了されます。

エラーが発生する原因

「role_ippan_a ロールに対して ADMIN OPTION が必要」というエラーメッセージの通り、付与者となるロールが付与するロールに対する ADMIN OPTION がないことが、エラーの発生理由となっています。

付与者となるロール(GRANTED BY オプション)

「付与者となるロール」というのは「GRANTED BY オプションに指定されたロール」が該当します。
GRANTED BY オプションが省略された場合は、「GRANT 文を実行するロール(v15以前)」または「postgres ロール(v16以降)」が GRANTED BY オプションに指定された扱いとなります。

PostgreSQL 文書の説明を下記に引用します。

【 PostgreSQL 16.4文書 - ロールに対するGRANT - 】
https://www.postgresql.jp/document/16/html/sql-grant.html#SQL-GRANT-DESCRIPTION-ROLES

GRANTED BYが指定された場合、付与は指定されたロールにより行なわれたと記録されます。 ユーザが別のロールに権限を付与できるのは、そのロールの権限を所有している場合のみです。
付与者として記録されるロールは、対象のロールに対してADMIN OPTIONを持っていることが必要です。

ただし、PostgreSQL 14 以前では「GRANT 文の実行するロールがロールの付与者である場合、ADMIN OPTION は不要」になるようです。
こちらも PostgreSQL 文書の該当箇所を下記に引用します。

【 PostgreSQL 14.5文書 - ロールに対するGRANT - 】
https://www.postgresql.jp/document/14/html/sql-grant.html#SQL-GRANT-DESCRIPTION-ROLES

ロールはそれ自体についてのWITH ADMIN OPTIONを保持しているとはみなされませんが、データベースセッションのユーザがロールにマッチする場合について、ロール内のメンバ資格を付与あるいは取り消しを行うことができます。

上記の説明は 15 以降の文書には記載がなくなっています。
そのため、PostgreSQL 14 以前ではエラーとならない GRANT 文が、PostgreSQL 15 以降ではエラーとなるようです。

実行するロールによって GRANT 文の成否が変わる

また、PostgreSQL 文書には記載がありませんが、「GRANT 文を実行するロールが postgres で、ロールを付与するロールも postgres の場合」には、ADMIN OPTION がなくてもエラーとなりません。
更に、ややこしいことに PostgreSQL 15 では「GRANT 文を実行するロールが SUPERUSER 属性」であれば、ADMIN OPTION がなくてもエラーとなりません。

一番の問題点

この「バージョンによって GRANT 文がエラーとなるかならないかが変わる」ことの一番の問題点は、「論理バックアップを利用したメジャーバージョンアップを行う際にエラーとなる可能性がある」点となります。

メジャーバージョンアップの際に、バージョンアップ元で pg_dumpall を利用して論理バックアップを出力し、それをバージョンアップ先にリストアすることでデータ移行する、ということがよく行われます。
例えば、PostgreSQL 14 から 17 へバージョンアップしたい場合、v14 の pg_dumpall を利用して論理バックアップを出力し、v17 の psql でバージョンアップ先へリストアする流れとなります。

pg_dumpall で出力された論理バックアップにも GRANT 文が含まれますので、バージョンアップ先でのリストアの際に "ERROR: permission denied to grant privileges as role <ロール名>" が発生する可能性があります。

さらに、リストア時にエラーが発生していることに気がつかなければ「動作はしているものの一部の処理でエラーが発生する」という、原因特定が難しい状況になってしまう可能性もあります。

pg_dumpall で出力される GRANT 文

また、pg_dumpall で出力される GRANT 文も、バージョンによって違いがあります。
PostgreSQL 15 以前の pg_dumpall で出力される GRANT 文には、自動的に GRANTED BY オプションが記述されます。
例えば、PostgreSQL 15 以前の PostgreSQL で

GRANT role_a TO role_b;

という GRANT 文を role_a ロールで実行したとします。
この場合、pg_dumpall の論理バックアップに含まれる GRANT 文は

GRANT role_a _to role_b GRANTED BY role_a;

となります。
この論理バックアップに含まれる GRANT 文を、PostgreSQL 16 以降ではエラーとなります。

改善

こういったリストア時のエラーに対応するため、PostgreSQL 16 で改善が行われています。
PostgreSQL 17.3 の pg_dumpall.c にあるコメントを下記に引用します。

Previous versions of PostgreSQL didn't used to track the grantor very
carefully in the backend, and the grantor could be any user even if
they didn't have ADMIN OPTION on the role, or a user that no longer
existed. To avoid dump and restore failures, don't dump the grantor
when talking to an old server version.

上記の通り、「GRANT 文を実行するロールが ADMIN OPTION を持っているかどうかを確認する」ということがコメントより読み取れます。
実際に PostgreSQL 16 以降の pg_dumpall で出力される GRANT 文は

GRANT role_a TO role_b GRANTED BY postgres;

となります(※ ADMIN OPTION を持っている状態で GRANT 文が実行されていた場合には、GRANTED BY の部分は role_a となります)。
この出力された GRANT 文は、「GRANT 文を実行するロールが postgres」で「GRANTED BY に指定されたロールも postgres」なため、エラーとなりません。

まとめ

以上が GRANT 文の実行時に発生する "ERROR: permission denied to grant privileges as role <ロール名>" エラーの原因の解説となります。
文章での説明がかなりややこしくなってしまいましたので、次回以降の記事で、バージョン間での GRANT 文の相違点などをまとめてみたいと思います。

CATEGORY

ARCHIVE

PostgreSQLに関するご相談は
株式会社インサイトまで
お気軽にお問い合わせください。

CONTACT