如何使用Golang Ping PostgreSQL?密码认证失败求助
问题详情
我尝试用Golang的lib/pq库连接PostgreSQL,执行db.Ping()时报错pq: password authentication failed for user "eos_user",但命令行工具(pg_isready、psql)都能正常操作数据库。
命令行正常操作示例
henry@vhost1:~/Eos$ pg_isready -h localhost -p 5432 -U eos_user -d eos_db localhost:5432 - accepting connections
henry@vhost1:~/Eos$ sudo -u eos_user psql -d eos_db -c "SELECT * FROM logs;" id | timestamp | level | message ----+----------------------------+-------+---------------- 1 | 2024-12-22 14:21:41.265223 | INFO | Test log entry 2 | 2024-12-22 14:24:09.661304 | INFO | Test log entry (2 rows) henry@vhost1:~/Eos$ sudo -u eos_user psql -d eos_db -c "INSERT INTO logs (level, message) VALUES ('INFO', 'Test log entry');" INSERT 0 1
Golang测试代码
package main import ( "database/sql" "fmt" "log" _ "github.com/lib/pq" ) func main() { host := "localhost" port := "5432" user := "eos_user" dbname := "eos_db" connStr := fmt.Sprintf("host=%s port=%s user=%s dbname=%s sslmode=disable", host, port, user, dbname) db, err := sql.Open("postgres", connStr) if err != nil { log.Fatalf("Failed to open database connection: %v", err) } defer db.Close() if err := db.Ping(); err != nil { log.Fatalf("Database is not ready: %v", err) } fmt.Println("Database is ready!") }
代码执行报错
henry@vhost1:~/Eos$ sudo -u eos_user go run testDbPing.go 2024/12/22 17:05:09 Database is not ready: pq: password authentication failed for user "eos_user" exit status 1
问题根源
命令行的psql未指定-h localhost时,默认使用Unix域套接字连接PostgreSQL,此时pg_hba.conf中对本地套接字的认证规则为peer(基于操作系统用户匹配),无需密码即可登录。
而Golang代码中指定了host=localhost,会触发TCP/IP连接,此时pg_hba.conf中对localhost的认证规则通常为md5或scram-sha-256(需要密码验证),但连接字符串未提供密码,因此触发认证失败。
解决方法
方法1:改用Unix域套接字连接
修改连接字符串,移除host和port参数,让lib/pq使用Unix域套接字连接(默认路径为/var/run/postgresql/.s.PGSQL.5432):
connStr := fmt.Sprintf("user=%s dbname=%s sslmode=disable", user, dbname)
若套接字路径非默认,可明确指定:
connStr := fmt.Sprintf("user=%s dbname=%s host=/var/run/postgresql sslmode=disable", user, dbname)
方法2:修改pg_hba.conf允许TCP连接使用peer认证
编辑PostgreSQL的pg_hba.conf文件(通常路径为/etc/postgresql/<版本号>/main/pg_hba.conf),找到IPv4本地连接规则:
# IPv4 local connections: host all all 127.0.0.1/32 scram-sha-256
将认证方式改为peer:
# IPv4 local connections: host all all 127.0.0.1/32 peer
修改后重启PostgreSQL服务:
sudo systemctl restart postgresql
方法3:添加密码到连接字符串
若需保留TCP连接,先给eos_user设置数据库密码,再在连接字符串中添加password参数:
connStr := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=你的数据库密码 sslmode=disable", host, port, user, dbname)
验证建议
优先尝试方法1,无需修改PostgreSQL配置,直接让Go代码与命令行使用相同的连接方式,最快解决问题。
内容的提问来源于stack exchange,提问作者chickenj0

