Chuyện gì đã xảy ra
Server của bạn bị crash — mất điện, OOM kill, kernel panic, hoặc bất cứ lý do nào đó — và bây giờ PostgreSQL từ chối khởi động. Lỗi bạn đang thấy:
FATAL: lock file "/var/run/postgresql/14-main.pid" already exists
HINT: Is another postmaster (PID 12345) running in data directory "/var/lib/postgresql/14/main"?
PostgreSQL ghi PID của mình vào file postmaster.pid khi khởi động. Khi tắt sạch, nó sẽ xóa file đó. Còn nếu crash? Không kịp xóa. File cũ vẫn còn đó, và lần khởi động tiếp theo sẽ thấy nó rồi từ chối boot — vì nó nghĩ đã có một instance khác đang chạy rồi.
Cách fix mất chưa đến hai phút. Nhưng trước tiên, hãy xác nhận PostgreSQL thực sự không đang chạy trước khi động vào bất cứ thứ gì.
Bước 1: Xác nhận không có gì đang thực sự chạy
Trước khi xóa bất cứ thứ gì, hãy loại trừ khả năng một tiến trình PostgreSQL thực sự vẫn còn sống:
# Kiểm tra xem có tiến trình postgres nào không
ps aux | grep postgres
# Kiểm tra xem có ai đang lắng nghe trên port mặc định không
sudo ss -tlnp | grep 5432
Nếu thấy tiến trình postgres đang hoạt động hoặc có thứ gì đó đang bind vào port 5432 thì dừng lại — có thể bạn đang có hai instance xung đột nhau. Hãy kiểm tra bằng pg_lsclusters (Debian/Ubuntu) trước khi làm bất cứ điều gì khác.
Không thấy gì? File PID chắc chắn là cũ. Tiến hành tiếp.
Bước 2: Kiểm tra nội dung file PID
cat /var/run/postgresql/14-main.pid
Dòng đầu tiên là PID mà PostgreSQL đã ghi lại khi khởi động lần cuối. Kiểm tra chéo lại:
ps -p 12345
No such process — hoặc một chương trình hoàn toàn khác tình cờ kế thừa PID đó — có nghĩa là file đã cũ và có thể xóa an toàn.
Bước 3: Xóa file lock cũ
sudo rm /var/run/postgresql/14-main.pid
Còn một file lock thứ hai nằm bên trong thư mục data. Kiểm tra xem có không:
sudo ls -la /var/lib/postgresql/14/main/postmaster.pid
Thấy rồi? Xóa cái đó luôn:
sudo rm /var/lib/postgresql/14/main/postmaster.pid
/var/run/postgresql/ chứa bản sao của init system; thư mục data chứa lock nội bộ của chính PostgreSQL. Sau một lần crash, cả hai đều trở nên cũ.
Bước 4: Khởi động PostgreSQL
sudo systemctl start postgresql@14-main
# Hoặc, nếu bạn dùng tên service chung:
sudo systemctl start postgresql
Theo dõi log ngay lập tức:
sudo journalctl -u postgresql@14-main -n 50 --no-pager
Bạn cần tìm dòng database system is ready to accept connections. Thấy rồi? Xong việc.
Bước 5: Xác nhận fix thành công
# Xác nhận service đang hoạt động
sudo systemctl status postgresql@14-main
# Kết nối và chạy thử kiểm tra nhanh
sudo -u postgres psql -c "SELECT version();"
Kiểm tra xem file PID mới đã được ghi đúng chưa:
cat /var/run/postgresql/14-main.pid
Nó phải chứa PID của tiến trình vừa được khởi động. Xác nhận nó khớp với một postgres đang chạy:
ps aux | grep postgres | head -5
Nếu PostgreSQL vẫn không chịu khởi động sau khi xóa file PID
File PID cũ không phải lúc nào cũng là vấn đề duy nhất sau một lần crash. Xem log PostgreSQL để tìm manh mối:
sudo tail -100 /var/log/postgresql/postgresql-14-main.log
Các vấn đề phổ biến hay đi kèm:
- Shared memory chưa được giải phóng — các phiên bản PostgreSQL cũ đôi khi để lại các segment shared memory. Liệt kê chúng bằng
ipcs -m, sau đó xóa các entry mồ côi:ipcrm -m <shmid>(ví dụ:ipcrm -m 327681). - Thư mục data cần recovery — thấy
database system was not properly shut downtrong log là bình thường sau crash. PostgreSQL sẽ replay WAL và tự phục hồi. Cứ để nó chạy — hầu hết database hoàn tất trong chưa đầy một phút. - Permissions bị thay đổi — xác nhận thư mục data vẫn thuộc sở hữu của
postgres:ls -la /var/lib/postgresql/14/. Sai owner? Sửa bằngsudo chown -R postgres:postgres /var/lib/postgresql/14/main.
Tham khảo nhanh: các file PID nằm ở đâu?
- Ubuntu/Debian PG 14:
/var/run/postgresql/14-main.pid - RHEL/CentOS/Fedora:
/var/run/postgresql/postmaster.pid - Lock trong thư mục data:
/var/lib/postgresql/14/main/postmaster.pid(hoặc nơiPGDATAcủa bạn trỏ tới) - Cài đặt tùy chỉnh: kiểm tra biến môi trường
PGDATAhoặc chạypg_lsclusters
Tại sao lỗi này cứ lặp lại (và cách giảm thiểu)
Nguyên nhân gốc rễ luôn là do tắt máy không sạch. Một vài điều đáng xem xét:
- UPS cho database server — thường bị bỏ qua nhiều nhất ở môi trường dev và staging. Đó chính xác là nơi lỗi này hay xuất hiện.
TimeoutStopSeccủa systemd — PostgreSQL bị kill giữa chừng khi reboot vì mất quá nhiều thời gian để flush? Hãy tăng timeout dừng lên. ThêmTimeoutStopSec=120vào service unit bằngsudo systemctl edit postgresql@14-main.- OOM killer — nếu Postgres bị OOM kill, đó là vấn đề hoàn toàn khác. Chạy
dmesg | grep -i oomsau khi crash để xác nhận. - VM snapshot — revert một VM đang chạy về snapshot sẽ để lại file PID cũ mỗi lần. Hãy tắt máy sạch trước khi snapshot, hoặc chấp nhận phải chạy qua cách fix này sau mỗi lần revert.
Cách fix này ít rủi ro. Cơ chế crash recovery dựa trên WAL của PostgreSQL tự xử lý tính toàn vẹn dữ liệu. Xóa file PID chỉ đơn giản là dọn sạch một artifact sổ sách mà vụ crash để lại.

