脱敏说明:文中 IP、主机名、账号口令均已脱敏,IP 第三段以
X占位;Schema / 实例名保留(属非凭据的内部标识)。环境:Linux + Oracle 19c,单主机双实例。
一、问题现象
在一套新的 UAT 环境(实例 XXMes,Schema XXX_UAT)上,照已有环境的样子新建了一条指向 ERP 测试库的 DB Link。建链语句执行成功,但一使用就报错:
ORA-01017: invalid username/password; logon denied
ORA-02063: 紧接着 line (起自 XXX_PRO_DBLINK)
二、环境拓扑
| 实例 | 主要 Schema | 角色 | DB Link |
|---|---|---|---|
XXMes | XXX_UAT | 新环境,链接报错 | ERP_PRO_DBLINK → 同一目标 |
两个实例跑在同一台数据库主机(192.168.X.26)上,共用同一个 ORACLE_HOME(/u01/app/oracle/product/19.0.0/dbhome_1)。
三、排查:把变量逐个排除
第 1 步 · 网络层
timeout 5 bash -c 'echo > /dev/tcp/192.168.X.166/1521' && echo TCP_OK
返回 TCP_OK,端口可达。
第 2 步 · 拿「能通的对照实例」验证远端账号
在已有环境的链接上做一次最小查询:
SELECT 'LINK_OK' AS result FROM dual@ERP_PRO_DBLINK;
返回 LINK_OK。说明同一个远端库、同一个远端账号,口令是有效的。
第 3 步 · 收敛差异
网络 ✅、服务名 ✅、远端账号 ✅ —— 唯一变动的只剩「建链时填写的口令」。
关键判据(很实用)
| 报错 | 含义 |
|---|---|
ORA-01017 | 远端认证失败 → 用户名 / 口令不对 |
ORA-12514 / ORA-12541 等(同样经 ORA-02063 抛出) | 网络 / 监听 / 服务名问题 |
ORA-02019 | 本端找不到这个 DB Link |
四、容易踩的坑:CREATE DATABASE LINK 不校验口令
CREATE DATABASE LINK 执行时不会去登录远端,所以口令填错也照样「创建成功」,要等到第一次真正使用才暴露。
实际现象就是:链接建了两次,都提示成功;直到第一次 select ... from dual@link 才报 ORA-01017。
结论:别把「建链成功」当成「链接可用」,建完必须跟一句验证查询。
五、想从数据库里读回旧链接口令?19c 做不到
三条路都试过,全部不通:
| 方法 | 结果 |
|---|---|
DBA_DB_LINKS | 只有 OWNER / DB_LINK / USERNAME / HOST,没有口令字段 |
DBMS_METADATA.GET_DDL('DB_LINK', ...) | 返回掩码:CONNECT TO "..." IDENTIFIED BY VALUES ':1' |
以 sysdba 查 SYS.LINK$ | PASSWORD 列为空;口令加密存于 PASSWORDX(RAW(128)),形如 0730EA5B…(略) |
19c 把 DB Link 口令设计成不可逆:即使 SYSDBA 也只能拿到密文,IDENTIFIED BY VALUES ':1' 也不是可用口令。
结论:DB Link 口令一旦丢失就无法从库内取回,只能重新设置;需要口径得找 ERP / DBA 侧要。
登 sysdba 的方式(root 不在 dba 组时需 su - oracle):
su - oracle -c 'export ORACLE_SID=<实例名>; sqlplus -S / as sysdba <<"EOF"
SELECT name, userid, password, passwordx FROM sys."LINK$";
EOF'
六、修复:不用删重建
-- 以链接所属 Schema 执行
ALTER DATABASE LINK "ERP_PRO_DBLINK" CONNECT TO "MES" IDENTIFIED BY "<正确口令>";
-- 回验
SELECT 'LINK_OK' AS result FROM dual@ERP_PRO_DBLINK;
SELECT <列> FROM <其他Schema>.<表>@ERP_PRO_DBLINK WHERE ROWNUM <= 5;
如果确实要删:
DROP DATABASE LINK "ERP_PRO_DBLINK"; -- 注意不是 DROP PUBLIC DATABASE LINK
七、建链参考(脱敏模板)
CREATE DATABASE LINK "ERP_PRO_DBLINK"
CONNECT TO "MES" IDENTIFIED BY "<口令>"
USING '(DESCRIPTION =(ADDRESS_LIST =(ADDRESS =(PROTOCOL = TCP)(HOST = 192.168.X.166)(PORT = 1521)))(CONNECT_DATA =(SERVICE_NAME = toptst)))';
两个注意点:
- 建在业务 Schema 下(例如
DMOM_UAT)。因为代码里写的是表名@ERP_PRO_DBLINK,不限定所有者,靠「当前会话 Schema + PUBLIC」解析;只有要给所有用户用时才建CREATE PUBLIC DATABASE LINK。 HOST里直接写完整 TNS 描述,不依赖tnsnames.ora,跨环境迁移更省事。
八、避坑清单
- 报错先分层:网络 → 监听 / 服务名 → 远端账号 → 口令 → 本端链接名,别一上来就查 SQL。
- 同主机多实例时,**优先找「能通的对照实例」**做最小验证,一步就能排除网络和服务名。
CREATE DATABASE LINK成功 ≠ 可用,建完必须验证。- 19c 起 DB Link 口令不可逆,别指望从
SYS.LINK$捞回明文,也别把IDENTIFIED BY VALUES ':1'当成口令。 - 注意区分 接口 API 口令(例如配置项
ERP.ApiPwd,值形如******)与 DB Link 口令 —— 两者完全无关,配置里能看到的那个口令救不了链接。 - 出现
ORA-01017时,第一反应应该是「口令」,而不是「权限」或「网络」。
九、常用查询备查
-- 全库 DB Link 清单
SELECT owner, db_link, username, host, created
FROM dba_db_links
ORDER BY owner, db_link;
-- 实际生效的 DB Link 定义(19c 口令在 PASSWORDX,需 sysdba)
SELECT name, userid, passwordx, host FROM sys."LINK$";
-- 本会话可见的链接
SELECT * FROM user_db_links; -- 仅自己拥有的
SELECT * FROM all_db_links; -- 自己有权限的 + PUBLIC