从 ORA-12547 到数据库恢复:一次目录 owner 与权限误改的完整排障记录

前言
运维人员误改 /u01 目录 owner 和权限后,报错 ORA-12547: TNS: lost contact
线上出这类问题,第一眼很容易被报错带偏。
看到:
sqlplus / as sysdba ORA-12547: TNS: lost contact
很多人第一反应会去怀疑监听、网络、实例状态,甚至怀疑数据库文件坏了。
但如果事故前刚做过下面这种操作:
chown -R test:test /u01
chmod -R 777 /u01
那基本就不用往网络方向想了,十有八九就是 Oracle 软件目录和运行目录的 owner、group、权限被改坏了。
这类问题我自己更愿意把它归类成“目录权限事故”,不是数据库故障本身,而是数据库运行环境先被人动坏了。
一、这类问题为什么会报 ORA-12547
ORA-12547: TNS: lost contact 这个报错本身比较迷惑,看上去像连接中断,实际上很多时候是 本地 Oracle 进程根本没有正常拉起来。
尤其是执行:
[oracle@centos7:/home/oracle]$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.4.0 Production on Mon Apr 6 18:42:39 2026 Copyright (c) 1982, 2013, Oracle. All rights reserved. ERROR: ORA-12547: TNS:lost contact Enter user-name: ERROR: ORA-12547: TNS:lost contact Enter user-name: ERROR: ORA-12547: TNS:lost contact SP2-0157: unable to CONNECT to ORACLE after 3 attempts, exiting SQL*Plus [oracle@centos7:/home/oracle]$
这种本地登录时,如果 Oracle 的可执行文件、依赖库、目录归属或者运行目录权限被改坏,sqlplus 这边看到的结果往往就是一句 lost contact。
简单说,不是 SQL*Plus 不会连,而是它把本地进程拉起来以后,对方刚起来就挂了。
如果前面有人把整个 /u01 都执行了:
[root@centos7:/root]# chown -R test:test /u01
[root@centos7:/root]# chmod -R 777 /u01
[root@centos7:/root]#
那受影响的一般不只是一个文件,而是整个 Oracle 目录树,包括:
/u01/app/oracle/u01/app/oraInventoryORACLE_HOMEORACLE_HOME/binORACLE_HOME/libORACLE_BASE/diagORACLE_BASE/adminORACLE_BASE/fast_recovery_area
所以这类问题,不能按“单文件权限错了”去理解。
二、这种事故最容易走错的一步
最容易犯的错误,是一看到 ORA-12547,马上去修:
chown oracle:oinstall $ORACLE_HOME/bin/oracle
chmod 6751 $ORACLE_HOME/bin/oracle
然后立刻就去试:
sqlplus / as sysdba
这个动作在“单个 binary 被改坏”的场景里有时候是对的。
但如果事故前提是整个 /u01 都被递归执行了 chown -R 和 chmod -R 777,那这一步通常不够。
因为这个时候坏掉的绝对不止 bin/oracle 一个文件。
也就是说,不能把“修 bin/oracle”写成第一步。第一步应该先把 Oracle 的目录体系拉回正常,再处理关键 binary。
三、正确的处理思路
我更建议按下面这个顺序来。
1. 先确认这是不是整个目录树都被改过
先把基础信息看清楚,不要一上来就乱改。
[oracle@centos7:/home/oracle]$ cat /etc/oraInst.loc
inventory_loc=/u01/app/oraInventory
inst_group=oinstall
[oracle@centos7:/home/oracle]$ id oracle
uid=54321(oracle) gid=54321(oinstall) groups=54321(oinstall),54322(dba),54323(oper),54324(backupdba),54325(dgdba),54326(kmdba),54330(racdba)
[oracle@centos7:/home/oracle]$ ls -ld /u01 /u01/app /u01/app/oracle /u01/app/oraInventory
drwxrwxrwx. 3 test test 17 Apr 6 17:35 /u01
drwxrwxrwx. 4 test test 40 Apr 6 17:35 /u01/app
drwxrwxrwx. 9 test test 132 Apr 6 18:33 /u01/app/oracle
drwxrwxrwx. 5 test test 89 Apr 6 17:36 /u01/app/oraInventory
[oracle@centos7:/home/oracle]$ ls -l $ORACLE_HOME/bin/oracle
-rwxrwxrwx. 1 test test 239501576 Apr 6 17:36 /u01/app/oracle/product/11.2.0/db/bin/oracle
[oracle@centos7:/home/oracle]$ stat -c '%U %G %a %n' $ORACLE_HOME/bin/oracle
test test 777 /u01/app/oracle/product/11.2.0/db/bin/oracle
[oracle@centos7:/home/oracle]$
这里主要看三件事:
第一、oracle 用户还在不在正确的组里。
第二、/u01/app/oracle 和 /u01/app/oraInventory 现在到底属于谁。
第三、$ORACLE_HOME/bin/oracle 是不是已经被改成了普通用户,而且特殊权限位也没了。
如果你看到类似这种情况:
/u01/app/oracle test:test
/u01/app/oraInventory test:test
$ORACLE_HOME/bin/oracle test:test 777
那基本可以直接判断:这不是单点故障,是整个目录树都被搞过了。
2. 第一件事,先把 Oracle 目录树 owner/group 拉回来
如果确认前面执行过:
chown -R test:test /u01
那第一步就应该先恢复 Oracle 目录树的归属,而不是先修改某一个 binary。
用 root 执行:
export ORACLE_BASE=/u01/app/oracle
export ORACLE_HOME=/u01/app/oracle/product/11.2.0/db
chown -R oracle:oinstall /u01/app/oracle
chown -R oracle:oinstall /u01/app/oraInventory
[root@centos7:/root]# export ORACLE_BASE=/u01/app/oracle
[root@centos7:/root]# export ORACLE_HOME=/u01/app/oracle/product/11.2.0/db
[root@centos7:/root]# chown -R oracle:oinstall /u01/app/oracle
[root@centos7:/root]# chown -R oracle:oinstall /u01/app/oraInventory
[root@centos7:/root]#
如果 /u01 和 /u01/app 也被改乱了,顺手把上层目录也摆正:
chown root:root /u01
chmod 755 /u01
chown root:root /u01/app
chmod 755 /u01/app
[root@centos7:/root]# chown root:root /u01
[root@centos7:/root]# chmod 755 /u01
[root@centos7:/root]# chown root:root /u01/app
[root@centos7:/root]# chmod 755 /u01/app
[root@centos7:/root]#
这一步非常关键。因为 Oracle 软件 owner、Inventory、Oracle Base、Oracle Home 这些东西,本来就应该是一套一致的归属体系。只修一个文件,意义不大。
3. 然后把目录权限从 777 收回来
既然前面做过:
chmod -R 777 /u01
那接下来必须把目录权限先收回来。
但是注意,不要再来一次:
chmod -R 755 /u01
这类一把梭的命令最容易把本来应该保留的特殊权限位一起抹平。
我习惯先只处理目录:
find /u01/app/oracle -type d -exec chmod 755 {} \;
find /u01/app/oraInventory -type d -exec chmod 755 {} \;
[root@centos7:/root]# find /u01/app/oracle -type d -exec chmod 755 {} \;
[root@centos7:/root]# find /u01/app/oraInventory -type d -exec chmod 755 {} \;
[root@centos7:/root]#
先保证目录是正常可进入、可遍历的,不再是到处 777 的状态。
4. 再修关键 binary
把目录体系和 owner/group 先拉回来以后,再回头修关键二进制文件,这个顺序才合理。
至少先修这些:
chown oracle:oinstall $ORACLE_HOME/bin/oracle
chmod 6751 $ORACLE_HOME/bin/oracle
[ -f $ORACLE_HOME/bin/orapwd ] && chown oracle:oinstall $ORACLE_HOME/bin/orapwd && chmod 751 $ORACLE_HOME/bin/orapwd
[ -f $ORACLE_HOME/bin/nid ] && chown oracle:oinstall $ORACLE_HOME/bin/nid && chmod 751 $ORACLE_HOME/bin/nid
[ -f $ORACLE_HOME/bin/wrap ] && chown oracle:oinstall $ORACLE_HOME/bin/wrap && chmod 751 $ORACLE_HOME/bin/wrap
[root@centos7:/root]# chown oracle:oinstall $ORACLE_HOME/bin/oracle
[root@centos7:/root]# chmod 6751 $ORACLE_HOME/bin/oracle
[root@centos7:/root]# [ -f $ORACLE_HOME/bin/orapwd ] && chown oracle:oinstall $ORACLE_HOME/bin/orapwd && chmod 751 $ORACLE_HOME/bin/orapwd
[root@centos7:/root]# [ -f $ORACLE_HOME/bin/nid ] && chown oracle:oinstall $ORACLE_HOME/bin/nid && chmod 751 $ORACLE_HOME/bin/nid
[root@centos7:/root]# [ -f $ORACLE_HOME/bin/wrap ] && chown oracle:oinstall $ORACLE_HOME/bin/wrap && chmod 751 $ORACLE_HOME/bin/wrap
[root@centos7:/root]#
这里面最关键的肯定是 bin/oracle。如果这个文件 owner、group 和模式位不对,本地登录经常就直接挂。
5. 不要偷懒,继续扫一遍残留文件
做到这里还不能急着说修好了。因为这种事故里,经常还会有少量文件残留成原来的错误 owner,比如:
- 某几个 binary
- 某几个
.so - jdk 下面的某个库文件
lib目录下的某个共享库
所以我一般会再扫一遍:
find $ORACLE_HOME \( -user test -o -group test \) | head -100
find /u01/app/oraInventory \( -user test -o -group test \) | head -100
[root@centos7:/root]# find $ORACLE_HOME \( -user test -o -group test \) | head -100
[root@centos7:/root]# find /u01/app/oraInventory \( -user test -o -group test \) | head -100
[root@centos7:/root]#
如果还有输出,就继续清到没有为止。
四、什么时候再去试 sqlplus
到这里再切回 oracle 用户去试,才比较合理:
su - oracle
sqlplus / as sysdba
[root@centos7:/root]# su - oracle
[oracle@centos7:/home/oracle]$ sqlplus / as sysdba
SQL*Plus: Release 11.2.0.4.0 Production on Mon Apr 6 20:43:23 2026
Copyright (c) 1982, 2013, Oracle. All rights reserved.
Connected to an idle instance.
SQL>
如果这时能看到:
Connected to an idle instance.
那说明前面这层 ORA-12547 基本已经过掉了。
五、如果能连上 idle instance,但 startup 又报错
这个场景很常见。
很多时候 ORA-12547 解决以后,sqlplus / as sysdba 已经能进了,但一执行 startup,又报:
ORA-48141: error creating directory during ADR initialization
ORA-48189: OS command to create directory failed
Linux-x86_64 Error: 13: Permission denied
这个本质上还是权限问题,只不过这次卡在了 ORACLE_BASE 的运行目录。
最常见的就是这些地方:
/u01/app/oracle/diag/u01/app/oracle/admin/u01/app/oracle/cfgtoollogs/u01/app/oracle/fast_recovery_area
这些目录如果还是 test:test,或者 Oracle 用户没有写权限,实例在启动时就会因为 ADR 初始化失败而报错。
所以这时候不要想太多,先查:
ls -ld /u01/app/oracle ls -ld /u01/app/oracle/diag ls -ld /u01/app/oracle/admin ls -ld /u01/app/oracle/fast_recovery_area
只要看到 owner 不对,就继续修:
chown -R oracle:oinstall /u01/app/oracle
确认没有残留后,再重新启动数据库。
[oracle@centos7:/home/oracle]$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.4.0 Production on Mon Apr 6 20:43:23 2026 Copyright (c) 1982, 2013, Oracle. All rights reserved. Connected to an idle instance. SQL> startup ORACLE instance started. Total System Global Area 2471931904 bytes Fixed Size 2255752 bytes Variable Size 620758136 bytes Database Buffers 1828716544 bytes Redo Buffers 20201472 bytes Database mounted. Database opened. SQL>
六、数据库起来以后,再看 listener
数据库能正常 startup 以后,再去处理监听:
lsnrctl start
[oracle@centos7:/home/oracle]$ lsnrctl start
LSNRCTL for Linux: Version 11.2.0.4.0 - Production on 06-APR-2026 20:47:14
Copyright (c) 1991, 2013, Oracle. All rights reserved.
Starting /u01/app/oracle/product/11.2.0/db/bin/tnslsnr: please wait...
TNSLSNR for Linux: Version 11.2.0.4.0 - Production
System parameter file is /u01/app/oracle/product/11.2.0/db/network/admin/listener.ora
Log messages written to /u01/app/oracle/diag/tnslsnr/centos7/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=centos7)(PORT=1521)))
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 11.2.0.4.0 - Production
Start Date 06-APR-2026 20:47:16
Uptime 0 days 0 hr. 0 min. 5 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/product/11.2.0/db/network/admin/listener.ora
Listener Log File /u01/app/oracle/diag/tnslsnr/centos7/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=centos7)(PORT=1521)))
The listener supports no services
The command completed successfully
[oracle@centos7:/home/oracle]$
刚启动 listener 时,如果看到:
The listener supports no services
这个时候先别误判成新故障。
很多时候只是 listener 刚起来,实例服务还没注册进去。
等一会儿再查一次,或者到数据库里执行:
alter system register;
[oracle@centos7:/home/oracle]$ sqlplus / as sysdba
SQL*Plus: Release 11.2.0.4.0 Production on Mon Apr 6 20:48:13 2026
Copyright (c) 1982, 2013, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> alter system register;
System altered.
SQL>
然后再看:
lsnrctl status
[oracle@centos7:/home/oracle]$ lsnrctl status
LSNRCTL for Linux: Version 11.2.0.4.0 - Production on 06-APR-2026 20:48:35
Copyright (c) 1991, 2013, Oracle. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 11.2.0.4.0 - Production
Start Date 06-APR-2026 20:47:16
Uptime 0 days 0 hr. 1 min. 18 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/product/11.2.0/db/network/admin/listener.ora
Listener Log File /u01/app/oracle/diag/tnslsnr/centos7/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=centos7)(PORT=1521)))
Services Summary...
Service "orcl" has 1 instance(s).
Instance "orcl", status READY, has 1 handler(s) for this service...
Service "orclXDB" has 1 instance(s).
Instance "orcl", status READY, has 1 handler(s) for this service...
The command completed successfully
[oracle@centos7:/home/oracle]$
正常的话,就能看到:
Service "orcl" has 1 instance(s).
Instance "orcl", status READY
到这里,基本就算收工了。
七、最后一定要做的两件事
1. 确认已经没有残留的错误 owner/group
find /u01/app/oracle \( -user test -o -group test \)
find /u01/app/oraInventory \( -user test -o -group test \)
[root@centos7:/root]# find /u01/app/oracle \( -user test -o -group test \)
[root@centos7:/root]# find /u01/app/oraInventory \( -user test -o -group test \)
[root@centos7:/root]#
最好都没有输出。
2. 确认关键 binary 已经恢复
stat -c '%U %G %a %n' $ORACLE_HOME/bin/oracle
[root@centos7:/root]# stat -c '%U %G %a %n' $ORACLE_HOME/bin/oracle
oracle oinstall 6751 /u01/app/oracle/product/11.2.0/db/bin/oracle
[root@centos7:/root]#
至少要确认 owner、group、模式位都已经回到 Oracle 正常使用的状态,而不是还挂着 test:test 或普通权限。
八、以后怎么避免再出这种事
说实话,这种事一旦发生,排起来都不难,真正难的是防止再来一次。
我的建议很简单:
第一、不要对 /u01 这种挂载点做无差别的递归 chown 和 chmod。
第二、不要把 Oracle 软件目录当普通业务目录处理。
第三、凡是涉及 ORACLE_HOME、ORACLE_BASE、oraInventory 的变更,先留快照,至少知道原来的 owner、group 和模式是什么。
第四,改完以后第一时间验证:
sqlplus / as sysdba lsnrctl status
别等业务报错了才知道出事。
九、另一种解决方案
也就是MOS上KB147561这篇文章。文章描述了如果有之前的目录权限的快照或者你重新安装和当前一样规划目录的Oracle软件,直接给出抓取权限快照 + 生成恢复脚本的方法:permission.pl 会生成 permission-
恢复步骤如下:
# 上传permission.pl文件到恢复快照或者重新安装和当前一样规划目录的Oracle软件的主机上,执行permission.pl捕获/u01目录所有权限。
[oracle@centos7new:/home/oracle]$ cd /home/oracle/script/
[oracle@centos7new:/home/oracle/script]$ chmod 755 permission.pl
[oracle@centos7new:/home/oracle/script]$ ./permission.pl /u01
Following log files are generated
logfile : permission-Mon-Apr-06-22-10-48-2026
Command file : restore-perm-Mon-Apr-06-22-10-48-2026.cmd
Linecount : 39509
[oracle@centos7new:/home/oracle/script]$
然后把restore-perm-Mon-Apr-06-22-10-48-2026.cmd文件上传到误改权限的主机上
# 确认目录和权限已经被破坏,执行restore-perm-Mon-Apr-06-22-10-48-2026.cmd,恢复正常
[oracle@centos7:/home/oracle]$ sqlplus / as sysdba
SQL*Plus: Release 11.2.0.4.0 Production on Mon Apr 6 22:24:03 2026
Copyright (c) 1982, 2013, Oracle. All rights reserved.
ERROR:
ORA-12547: TNS:lost contact
Enter user-name:
ERROR:
ORA-12547: TNS:lost contact
Enter user-name:
ERROR:
ORA-12547: TNS:lost contact
SP2-0157: unable to CONNECT to ORACLE after 3 attempts, exiting SQL*Plus
[oracle@centos7:/home/oracle]$ ls -lh $ORACLE_HOME/bin/oracle
-rwxrwxrwx. 1 test test 229M Apr 6 17:36 /u01/app/oracle/product/11.2.0/db/bin/oracle
[oracle@centos7:/home/oracle/script]$ exit
[root@centos7:/root]# chmod +x restore-perm-Mon-Apr-06-22-10-48-2026.cmd
[root@centos7:/root]# ./restore-perm-Mon-Apr-06-22-10-48-2026.cmd
[root@centos7:/root]# su - oracle
[oracle@centos7:/home/oracle]$ ls -lh $ORACLE_HOME/bin/oracle
-rwsr-s--x. 1 oracle oinstall 229M Apr 6 17:36 /u01/app/oracle/product/11.2.0/db/bin/oracle
[oracle@centos7:/home/oracle]$ sqlplus / as sysdba
SQL*Plus: Release 11.2.0.4.0 Production on Mon Apr 6 22:26:08 2026
Copyright (c) 1982, 2013, Oracle. All rights reserved.
Connected to an idle instance.
SQL> startup
ORACLE instance started.
Total System Global Area 2471931904 bytes
Fixed Size 2255752 bytes
Variable Size 620758136 bytes
Database Buffers 1828716544 bytes
Redo Buffers 20201472 bytes
Database mounted.
Database opened.
SQL> exit
Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
[oracle@centos7:/home/oracle]$ lsnrctl start
LSNRCTL for Linux: Version 11.2.0.4.0 - Production on 06-APR-2026 22:26:20
Copyright (c) 1991, 2013, Oracle. All rights reserved.
Starting /u01/app/oracle/product/11.2.0/db/bin/tnslsnr: please wait...
TNSLSNR for Linux: Version 11.2.0.4.0 - Production
System parameter file is /u01/app/oracle/product/11.2.0/db/network/admin/listener.ora
Log messages written to /u01/app/oracle/diag/tnslsnr/centos7/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=centos7)(PORT=1521)))
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 11.2.0.4.0 - Production
Start Date 06-APR-2026 22:26:20
Uptime 0 days 0 hr. 0 min. 0 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/product/11.2.0/db/network/admin/listener.ora
Listener Log File /u01/app/oracle/diag/tnslsnr/centos7/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=centos7)(PORT=1521)))
The listener supports no services
The command completed successfully
[oracle@centos7:/home/oracle]$
文末分享MOS中的权限提取permission.pl脚本 下载链接 方便读者在有限的条件下挽救环境,快速恢复数据库可用。
十、总结
这次故障表面上看是 ORA-12547: TNS: lost contact,但本质并不是监听问题,也不是数据库文件本身损坏,而是运维人员误对 /u01 整个目录执行了递归 chown 和 chmod,把 Oracle 的软件目录、Inventory、关键 binary 以及运行目录的 owner、group 和权限体系全部打乱了。




