できない.dev

PostgreSQL で「Peer authentication failed for user」が出て接続できない

Peer authentication failed for user は、OS のユーザー名と DB のユーザー名が違うと出る。
同名の OS ユーザーで実行するか、TCP 接続かパスワード認証へ切り替えれば直る。

公開: 更新:

要約

peer 認証は、Peer Authentication(新しいタブで開く) が説明するとおり クライアントの OS ユーザー名をカーネルから取得し、それをそのまま許可するデータベースユーザー名として扱う。
パスワードは一切見ない。
だから OS 側で alice としてログインしている限り、myuser としては入れない。

psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed:
FATAL:  Peer authentication failed for user "myuser"

エラーに socket と出ているのが手掛かりで、これは Unix ドメインソケット経由の接続を意味する。
peer はローカル接続でのみ使える方式なので、TCP に切り替えるだけでも別の行が適用される。

解決策

1. OS ユーザーを合わせる

sudo -u postgres psql

管理作業なら、これが最も手数が少ない。postgres ロールで入ったあと、必要なロールやデータベースを作る。

2. TCP 接続に切り替える

psql -h 127.0.0.1 -p 5432 -U myuser -d mydb

-h を付けると pg_hba.conf の host 行が使われる。
アプリケーションからの接続は元々こちらなので、症状が psql でだけ出る場合はこの違いが原因である。

3. パスワード認証に変える

# TYPE  DATABASE  USER  ADDRESS  METHOD
local   all       all            scram-sha-256

The pg_hba.conf File(新しいタブで開く) が定めるとおり、上から順に最初に一致した行だけが使われる。peer の行が上に残っていると書き換えたつもりでも効かないので、順序も確認する。

4. ユーザー名マップを使う

pg_ident.conf:

# MAPNAME  SYSTEM-USERNAME  PG-USERNAME
app        deploy           myuser
app        postgres         postgres

pg_hba.conf:

local   all   all   peer map=app

OS の deploy で myuser として入れるようになる。
パスワードを持たせずに済むので、サーバー上のデプロイ用アカウントに向く。

2 行目の postgres postgres も必要である。map= を付けた行では、OS ユーザー名と DB ユーザー名が同じでも自動では通らず、User Name Maps(新しいタブで開く) のとおりマップに書いた組み合わせだけが許可される。local all all の行にマップを付けると、その行に当たる全接続が対象になるので、deploy の 1 行だけでは sudo -u postgres psql まで弾かれる。
影響を絞りたい場合は、local all myuser peer map=app のように USER 列を限定した行を既存の local all all peer より上に置く。

5. 設定を再読み込みする

sudo systemctl reload postgresql

または接続済みのセッションから次を実行する。

SELECT pg_reload_conf();

実際に適用された内容は SELECT * FROM pg_hba_file_rules; で確認できる。
構文エラーがあれば error 列に出るので、再読み込みが黙って失敗している場合の切り分けに使える。

よくある原因

  1. OS ユーザーと DB ユーザーの不一致: Debian / Ubuntu のパッケージは local all all peer を既定にしている。
    自分の OS アカウントのまま -U myuser を指定すれば必ず落ちる。
  2. パスワードを設定したのに使われない: ALTER ROLE myuser PASSWORD ... を実行しても、pg_hba.conf が peer のままならパスワードは参照されない。
    「パスワードが違う」と誤解しやすい。
  3. 接続経路の取り違え: -h を付けない psql はソケット接続になる。-h 127.0.0.1 を付けると host 行が使われ、認証方式が変わる。
  4. ユーザー名マップ未定義: OS ユーザー名と DB ユーザー名を意図的に分けたい場合は pg_ident.conf にマップが要る。
    書かないまま peer を使えば一致しない。
  5. 再読み込み漏れ: pg_hba.conf は起動時と再読み込み時にしか反映されない。
    編集しただけでは変わらない。

この手順で直った?