TL;DR
/etc/postgresql/*/main/pg_hba.confを開き、peer認証方式をmd5(PostgreSQL 14以降はscram-sha-256)に変更し、PostgreSQLをリロードします。
# 変更前:
local all all peer
# 変更後:
local all all md5
sudo systemctl reload postgresql
エラーの内容
FATAL: Peer authentication failed for user "myapp"
このエラーは、ローカルUnixソケット経由でPostgreSQLに接続する際、OSのユーザー名が要求しているPostgreSQLロールと一致しない場合に発生します。重要な点として、これはパスワードの誤りとは無関係です。Peer認証はパスワードをまったく確認しません。
根本原因
内部では、pg_hba.conf(ホストベース認証)がすべての接続の認証方法を制御しています。peer方式はOSに「現在のユーザーは誰か?」と問い合わせ、その名前が要求されたPostgreSQLロールと一致するかを確認します。
ubuntuとしてログインしている状態で次を実行したとします:
psql -U postgres
PostgreSQLはOSユーザーubuntuと要求ロールpostgresを確認します。一致しないため—拒否されます。Debian/Ubuntuの多くのインストールではデフォルトでこの設定が使われています:
local all postgres peer
local all all peer
sudo -u postgres psql経由のシステムレベルアクセスには問題ありません。しかし、アプリが自身の認証情報で接続しようとした瞬間に、Peer認証が接続を拒否します。
修正方法
オプション1:md5またはscram-sha-256に切り替える(最も一般的な修正方法)
まず、pg_hba.confの場所を確認します:
# PostgreSQLに直接確認:
sudo -u postgres psql -c "SHOW hba_file;"
# 一般的なパス:
# Debian/Ubuntu: /etc/postgresql/14/main/pg_hba.conf
# RHEL/CentOS: /var/lib/pgsql/14/data/pg_hba.conf
ファイルを開き、local行のpeerをmd5に変更します:
sudo nano /etc/postgresql/14/main/pg_hba.conf
# これを:
local all all peer
# これに変更:
local all all md5
PostgreSQL 14以降では、scram-sha-256がより良い選択肢です。このバージョンでデフォルトのパスワード暗号化になり、MD5より大幅に強固です:
local all all scram-sha-256
アクティブな接続を切断せずに設定を適用するためにリロードします:
sudo systemctl reload postgresql
もう一点:データベースユーザーに実際にパスワードが設定されているか確認してください。
sudo -u postgres psql
ALTER USER myapp WITH PASSWORD 'your_password_here';
\q
オプション2:一致するOSユーザーとして接続する
peer認証を維持したい場合は、コマンドを実行するOSユーザーとPostgreSQLロールを一致させる必要があります:
# postgresスーパーユーザーの場合:
sudo -u postgres psql
# アプリ専用ユーザーの場合:
sudo -u myapp psql -d myapp_db
単発のメンテナンス作業には便利ですが、独自に認証する必要があるアプリケーション接続には使えません。
オプション3:特定ユーザーのみに変更を適用する
全員をパスワード認証に切り替える代わりに、デフォルトのキャッチオールの上に特定のルールを追加します。pg_hba.confのルールは上から下に照合され、最初に一致したものが適用されます。
# pg_hba.conf — 具体的なルールを先に記述:
local myapp_db myapp md5
local all all peer
これにより、myappはmyapp_dbに対してパスワードで認証し、postgresスーパーユーザーとその他はPeer認証を維持します。
オプション4:UnixソケットのかわりにTCPを使用する
あまり知られていない回避策です。Unixソケット接続はpg_hba.confのlocalルールに従います。127.0.0.1への接続も含むTCP接続はhostルールに従い、通常デフォルトでmd5が使われます:
psql -h 127.0.0.1 -U myapp -d myapp_db
hostの行がパスワード認証を許可していることを確認します:
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
pg_hba.conf 認証方式リファレンス
- peer — OSユーザー名がDBロールと一致している必要があります。パスワードは確認されません。ローカルソケット専用。
- md5 — パスワードが必要で、MD5ハッシュとして保存されます。すべてのクライアントで広くサポートされています。
- scram-sha-256 — パスワードが必要で、より強固なハッシュを使用します。サーバーとクライアントの両方でPostgreSQL 10以降が必要です。
- trust — 認証なし。ローカル開発専用 — 本番環境では絶対に使用しないでください。
- reject — 常に拒否します。特定のIPやユーザーを明示的にブロックするのに便利です。
修正の確認
# アプリユーザーとして接続:
psql -U myapp -d myapp_db
# このようなプロンプトが表示されるはずです:
# myapp_db=>
# ユーザーにパスワードが設定されているか確認:
sudo -u postgres psql -c "SELECT usename, passwd IS NOT NULL AS has_password FROM pg_shadow WHERE usename = 'myapp';"
# pg_hbaルールが正しく読み込まれているか確認:
sudo -u postgres psql -c "SELECT * FROM pg_hba_file_rules;"
接続時にpeerエラーが出なければ完了です。
補足
パスワードベース認証に切り替えると、すべてのデータベースユーザーに実際のパスワードが必要になります — このステップを省略しないでください。強力なパスワードを生成する必要がある場合、ToolCraftのパスワードジェネレーターはすべてブラウザ内で動作し、サーバーには何も送信されません。データベース認証情報を作成する際に知っておく価値があります。
また、pg_hba.confを編集した後は、restartではなく必ずreloadを使用してください。リロードは既存の接続に影響を与えずに新しい設定を新規接続に適用します。restartが必要なのはpostgresql.confの変更のみです — PostgreSQLがどの変更に再起動が必要かを教えてくれます。
# 既存接続を中断しないリロード:
sudo systemctl reload postgresql
# またはpsql内から:
SELECT pg_reload_conf();

