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ế độ700thuộ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 và /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 userpostgres. 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ộ.

