PostgreSQL pg_dump执行失败:含特殊字符密码的认证错误
我尝试通过PostgreSQL存储过程执行pg_dump命令,使用EXECUTE format动态构建命令,相关代码如下:
'COPY (SELECT 1) TO PROGRAM ''script -c "PGPASSWORD=%s pg_dump -h %s -p %s -U %s -Z6 -Fc -v -d %s -t %s -f %s%s.sql" %s%s_log.txt''', ppassword, phost, pport, pusername, pdbname, atablename, pdumppath, atablename, plogdumppath, atablename );
当使用用户和密码postgres时可正常运行,但当ppassword值包含@ddG$fG#2@91这类特殊字符时,出现如下错误:
FATAL: password authentication failed for user "user_name"
connection to server at "ip_address", port xxxx failed:
FATAL: password authentication failed for user "user_name"
已确认用户名、主机、端口、数据库名、表名均正确且权限与postgres用户一致,手动在PGPASSWORD环境变量或psql中使用该密码可正常登录,问题似乎出在密码中的特殊字符。
PostgreSQL版本:PostgreSQL 16.4 (Ubuntu 16.4-1.pgdg22.04+1) on x86_64-pc-linux-gnu,编译环境为gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0,64位。
请问在此场景下如何正确传递这类含特殊字符的密码?
问题核心是特殊字符在shell命令中被解析转义,直接用%s拼接会导致密码中的特殊字符(如$、#、@)被shell当作特殊符号处理,而非作为密码的一部分传递给pg_dump。以下是两种可行的解决方法:
方法1:使用quote_literal()函数转义密码
PostgreSQL提供的quote_literal()函数会给字符串添加单引号,并自动转义内部的特殊字符,确保shell将其识别为完整的字符串。修改后的代码如下:
'COPY (SELECT 1) TO PROGRAM ''script -c "PGPASSWORD=%s pg_dump -h %s -p %s -U %s -Z6 -Fc -v -d %s -t %s -f %s%s.sql" %s%s_log.txt''', quote_literal(ppassword), phost, pport, pusername, pdbname, atablename, pdumppath, atablename, plogdumppath, atablename );
方法2:使用format()的%L占位符
format()函数的%L占位符会自动对字符串进行字面量转义,效果与quote_literal()一致,代码更简洁:
EXECUTE format( 'COPY (SELECT 1) TO PROGRAM ''script -c "PGPASSWORD=%L pg_dump -h %s -p %s -U %s -Z6 -Fc -v -d %s -t %s -f %s%s.sql" %s%s_log.txt''', ppassword, phost, pport, pusername, pdbname, atablename, pdumppath, atablename, plogdumppath, atablename );
额外建议:更安全的密码传递方式
命令行传递密码存在安全风险(可能被ps等工具捕获),更优的方案是:
- 使用
.pgpass文件存储密码,pg_dump会自动读取该文件,无需在命令行指定PGPASSWORD - 若必须在存储过程中传递,可通过设置会话环境变量的方式,但需确保变量值被正确转义
内容的提问来源于stack exchange,提问作者codeanonym

