Sửa lỗi PostgreSQL 'could not open file for reading: Permission denied' với lệnh 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

Lỗi Gặp Phải

Bạn chạy lệnh COPY để import file CSV và nhận được lỗi này:

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

File đang nằm ngay đó. Bạn dùng cat đọc bình thường. Vậy mà PostgreSQL vẫn từ chối. Nguyên nhân là PostgreSQL đọc file với tư cách OS user postgres — không phải bạn. Và postgres không có quyền truy cập vào đường dẫn đó.

Tại Sao Xảy Ra Lỗi Này

Lệnh COPY FROM phía server chạy dưới tài khoản hệ thống postgres. Có hai điểm thường khiến mọi người bị nhầm:

  • File không cho phép postgres đọc.
  • Một thư mục cha trong đường dẫn chặn postgres đi qua — không có bit execute (x). File có thể là 777 nhưng vẫn không hoạt động nếu /var/data/ ở chế độ 700 thuộc sở hữu của người dùng khác.

Lưu ý: đây là lệnh COPY phía server, không phải \copy. Lệnh client psql \copy chạy với tư cách của bạn. Hoàn toàn khác nhau — chi tiết ở phần bên dưới.

Cách Khắc Phục Từng Bước

Bước 1 — Kiểm tra chủ sở hữu file

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

Kết quả thường thấy trên server Ubuntu mới cài:

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

Chế độ 700 trên thư mục có nghĩa chỉ ubuntu mới vào được. User postgres bị chặn ngay từ trước khi tới được file.

Bước 2 — Xác nhận PostgreSQL chạy với user nào

ps aux | grep postgres | head -3

Cột đầu tiên là OS user. Trên hầu hết hệ thống là postgres, nhưng một số cài đặt tùy chỉnh dùng tài khoản khác — nên kiểm tra cho chắc.

Bước 3 — Cấp quyền đọc cho file

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

Dạng số tương đương:

chmod 644 /var/data/import.csv

Bước 4 — Cấp quyền execute cho mọi thư mục trong đường dẫn

PostgreSQL phải đi qua mọi thư mục trong đường dẫn, không chỉ thư mục cuối. Với /var/data/import.csv, cả /var/var/data đều cần bit execute cho postgres. Hầu hết hệ thống để /var ở chế độ world-executable mặc định, nhưng /var/data thường bị khóa:

chmod o+x /var/data/

Với đường dẫn sâu hơn như /home/ubuntu/data/imports/, cần thêm o+x cho từng phần. Xử lý từng cái một.

Bước 5 — Chạy lại lệnh COPY

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

Không còn lỗi phân quyền nữa.

Cách Khác: Di Chuyển File Vào /tmp

Không muốn mở quyền thư mục? Chỉ cần sao chép file vào nơi PostgreSQL đã có thể truy cập:

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

Rồi chạy import từ đó:

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

Dọn dẹp khi xong:

rm /tmp/import.csv

Nhanh và ít rủi ro cho các lần import không thường xuyên.

Cách Khác: Dùng \copy

Đang chạy câu lệnh qua psql? Bỏ lệnh SQL COPY và dùng \copy thay thế:

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

Lệnh này chạy phía client với user của bạn. Không còn vấn đề phân quyền phía server. Với file lớn — ví dụ 500 MB trở lên — có thể chậm hơn một chút vì dữ liệu phải đi qua kết nối client. Dưới 100 MB thì bạn sẽ không thấy sự khác biệt.

Kết nối tới server PostgreSQL từ xa với file CSV trên máy cục bộ? \copy là lựa chọn duy nhất vì lệnh COPY phía server không thể truy cập filesystem trên máy tính của bạn.

Kiểm Tra Trước Khi Import

Cách kiểm tra nhanh nhất — giả lập user postgres và thử đọc file trực tiếp:

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

In ra được năm dòng mà không báo lỗi? PostgreSQL có thể đọc được. Vẫn thấy Permission denied? Một thư mục trong đường dẫn vẫn chưa đúng quyền — quay lại Bước 4.

Mẹo Thêm

Kiểm tra lại giá trị chmod bằng mắt

Các giá trị octal như 644 hay 640 rất dễ nhầm lẫn, đặc biệt khi cần phân quyền khác nhau cho owner, group và others. Unix Permissions Calculator trên ToolCraft cho phép bạn xem chính xác một giá trị chmod cho phép gì trước khi áp dụng — nhanh hơn nhiều so với tự giải mã octal trong đầu.

Ưu tiên dùng group ownership thay vì world-readable

Mở file với o+r có nghĩa mọi user trên hệ thống đều đọc được. Cách an toàn hơn: tạo một group dùng chung, thêm postgres vào đó, và dùng quyền group thay thế.

# 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

Các user khác trên máy không thể đụng vào file. Gọn gàng hơn nhiều trong môi trường dùng chung.

Với import định kỳ, dùng thư mục staging riêng

Nếu import thường xuyên, hãy tạo một thư mục mà postgres sở hữu hoàn toàn:

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

Đưa file vào đó trước mỗi lần import. Lỗi phân quyền sẽ không còn là vấn đề — postgres sở hữu toàn bộ thư mục.

COPY và \copy — so sánh nhanh

  • COPY — lệnh SQL. Chạy trên database server. Dùng quyền OS user postgres. File phải tồn tại trên server.
  • \copy — meta-command của psql. Chạy trên máy client của bạn. Dùng quyền OS user của bạn. File có thể ở bất kỳ đâu trên máy cục bộ.

Related Error Notes