PostgreSQLの「could not open file for reading: Permission denied」をCOPYコマンドで修正する

beginner🐘 PostgreSQL2026-04-28| PostgreSQL 12〜16、Linux(Ubuntu、Debian、CentOS、RHEL)、macOS

Error Message

ERROR: could not open file "/var/data/import.csv" for reading: Permission denied
#postgresql#copy#permission#csv#import

エラーの内容

CSVファイルをインポートするために COPY コマンドを実行したところ、以下のエラーが表示された:

ERROR:  could not open file "/var/data/import.csv" for reading: Permission denied

ファイルはそこに存在している。cat で確認しても問題ない。それでも PostgreSQL は拒否する。なぜなら、PostgreSQL はファイルを postgres OSユーザーとして読み込むからだ — あなたのユーザーとしてではない。そして postgres はそのパスにアクセスする権限を持っていない。

なぜこのエラーが起きるのか

サーバーサイドの COPY FROMpostgres システムアカウントで実行される。よくある落とし穴が2つある:

  • ファイルが postgres によって読み取れない。
  • パス中の親ディレクトリが postgres のトラバースをブロックしている — 実行(x)ビットがない。ファイルが 777 でも、/var/data/ が別ユーザー所有でモード 700 なら動かない。

注意:これはサーバーサイドの COPY であり、\copy ではない。psql クライアントコマンド \copyあなたのユーザーとして実行される。全く別物だ — 詳しくは後述する。

ステップごとの解決方法

ステップ 1 — ファイルの所有者を確認する

ls -la /var/data/import.csv
ls -la /var/data/

Ubuntu サーバーの初期状態での典型的な出力:

-rw------- 1 ubuntu ubuntu 204800 Apr 27 10:00 /var/data/import.csv
drwx------ 2 ubuntu ubuntu   4096 Apr 27 09:55 /var/data/

ディレクトリのモードが 700 の場合、ubuntu のみが入れる。postgres ユーザーはファイルに到達する前にブロックされる。

ステップ 2 — PostgreSQL が実行されているユーザーを確認する

ps aux | grep postgres | head -3

最初のカラムが OSユーザーだ。ほとんどのシステムでは postgres だが、カスタムインストールでは別のアカウントを使う場合もある — 確認する価値がある。

ステップ 3 — ファイルの読み取り権限を付与する

chmod o+r /var/data/import.csv

数値形式での同等コマンド:

chmod 644 /var/data/import.csv

ステップ 4 — パス上の全ディレクトリに実行権限を付与する

PostgreSQL はパス上のすべてのディレクトリをトラバースする必要がある。最後のディレクトリだけではない。/var/data/import.csv の場合、/var/var/data の両方に postgres の実行ビットが必要だ。多くのシステムでは /var はデフォルトで全ユーザーに実行権限があるが、/var/data はしばしばロックされている:

chmod o+x /var/data/

/home/ubuntu/data/imports/ のような深いパスは、各セグメントに o+x が必要だ。一つずつ確認していこう。

ステップ 5 — COPY コマンドを再実行する

COPY your_table FROM '/var/data/import.csv' WITH (FORMAT csv, HEADER true);

権限エラーは出なくなる。

代替案:ファイルを /tmp に移動する

ディレクトリを開放したくない場合は、PostgreSQL がすでにアクセスできる場所にファイルをコピーするだけでよい:

cp /var/data/import.csv /tmp/import.csv
chmod 644 /tmp/import.csv

そこからインポートを実行する:

COPY your_table FROM '/tmp/import.csv' WITH (FORMAT csv, HEADER true);

完了したら後片付けをする:

rm /tmp/import.csv

一回限りのインポートには手軽でリスクが低い方法だ。

代替案:\copy に切り替える

psql でクエリを実行しているなら? SQL の COPY をやめて代わりに \copy を使おう:

\copy your_table FROM '/var/data/import.csv' WITH (FORMAT csv, HEADER true);

クライアントサイドで自分のユーザーとして実行される。サーバーサイドの権限問題は発生しない。大きなファイル — たとえば 500 MB 以上 — の場合、データがクライアント接続を経由するためわずかなパフォーマンスコストがある。100 MB 未満なら差を感じることはないだろう。

ローカルマシン上の CSV を使ってリモートの PostgreSQL サーバーに接続する場合、サーバーサイドの COPY はノートパソコンのファイルシステムにアクセスできないため、いずれにしても \copy 一択となる。

インポート前に確認する

最速のサニティチェック — postgres ユーザーに成り代わり、ファイルを直接読み込んでみる:

sudo -u postgres cat /var/data/import.csv | head -5

エラーなしで5行が表示されたなら、PostgreSQL は読み込める。それでも Permission denied が出る場合、パス上のどこかのディレクトリの権限が誤っている — ステップ 4 を見直そう。

Tips

chmod の値を視覚的に確認する

644640 のような8進数モードは、所有者・グループ・その他で異なるアクセス権が必要な場合に混同しやすい。ToolCraft の Unix Permissions Calculator を使えば、適用前に chmod の値が何を許可するかを正確に確認できる — 頭の中で8進数を解読するより圧倒的に速い。

world-readable よりグループ所有権を優先する

ファイルを o+r にするとシステム上の全ユーザーが読み取れるようになる。より厳密なアプローチ:共有グループを作成し、postgres を追加して、グループ権限を使う。

# Create a shared group and add postgres to it
sudo groupadd dataimport
sudo usermod -aG dataimport postgres

# Set group ownership
chown :dataimport /var/data/
chown :dataimport /var/data/import.csv

# Only owner and group can access
chmod 750 /var/data/
chmod 640 /var/data/import.csv

サーバー上の他のユーザーはファイルにアクセスできない。共有環境では圧倒的にクリーンだ。

定期的なインポートには専用のステージングディレクトリを使う

定期的にインポートを行う場合は、postgres が完全に所有するディレクトリを用意しよう:

sudo mkdir -p /var/pgimport
sudo chown postgres:postgres /var/pgimport
sudo chmod 700 /var/pgimport

インポートのたびにそこにファイルを配置する。postgres がディレクトリ全体を所有しているため、権限エラーは起きなくなる。

COPY と \copy — クイックリファレンス

  • COPY — SQL コマンド。データベースサーバー上で実行される。postgres OSユーザーの権限を使用する。ファイルはサーバー上に存在する必要がある。
  • \copy — psql メタコマンド。クライアントマシン上で実行される。自分の OSユーザーの権限を使用する。ファイルはローカルマシン上のどこにあってもよい。

Related Error Notes