ora-01031报错需先排查会话角色、对象属主、默认表空间、密码文件权限、cdb/pdb上下文及账户状态;权限分system与object两类,“any”类权限应严格限制,角色须显式启用,pdb权限需单独授予。
ora-01031 报错时,先确认当前用户能干啥
ora-01031 不是“没权限”的模糊提示,而是 oracle 明确拒绝了你正在执行的操作——但拒绝原因可能藏在操作类型、对象属主、角色激活状态里。直接 grant dba 给用户是高危操作,得先摸清边界。
用 SELECT * FROM SESSION_ROLES; 查当前会话已启用的角色;再查 SELECT * FROM ROLE_TAB_PRIVS WHERE ROLE IN (SELECT ROLE FROM SESSION_ROLES); 看这些角色实际能访问哪些表。很多情况下,CREATE TABLE 失败不是因为没 CREATE TABLE 权限,而是用户默认表空间没配、或 UNLIMITED TABLESPACE 没给。
- 连接后立刻执行
SHOW USER;和SELECT USERNAME, DEFAULT_TABLESPACE, TEMPORARY_TABLESPACE FROM DBA_USERS WHERE USERNAME = SYS_CONTEXT('USERENV', 'SESSION_USER'); - 如果操作的是其他用户下的对象(比如
SELECT * FROM scott.emp;),权限必须由scott显式GRANT SELECT ON emp TO your_user;,role 里的权限不跨 schema 生效 -
ALTER SYSTEM、DROP DATABASE这类语句,普通用户永远拿不到权限,必须用SYSDBA或SYSOPER连接
GRANT 之前,分清 system privilege 和 object privilege
Oracle 权限分两大类:system privilege(对整个实例生效,如 CREATE SESSION)和 object privilege(针对具体对象,如 SELECT ON hr.employees)。混用会导致授权无效或过度放权。
比如你想让应用用户能查 hr.departments,只给 SELECT ANY TABLE 是错的——它能查所有用户的所有表,且属于高危 system privilege;正确做法是 GRANT SELECT ON hr.departments TO app_user;。
-
SELECT ANY TABLE、UPDATE ANY TABLE等 “ANY” 权限应严格限制在运维账号,绝不用于应用连接用户 - 授予 object privilege 时,必须由对象属主(如
hr)执行,或由有GRANT ANY OBJECT PRIVILEGE的用户代授 - 角色(role)可以包含 system 和 object privilege,但 role 必须被
SET ROLE显式启用,否则不生效——很多脚本连上就跑 SQL,忘了这步
使用 IDENTIFIED BY VALUES 时,密码文件权限别漏掉
当你用 CONNECT / AS SYSDBA 或远程用 sqlplus sys/oracle@db AS SYSDBA 报 ORA-01031,大概率不是密码错,而是 Oracle 没读到有效的密码文件,或文件权限不对。
密码文件路径通常是 $ORACLE_HOME/dbs/orapw<oracle_sid></oracle_sid>(Linux)或 %ORACLE_HOME%\database\pwd<oracle_sid>.ora</oracle_sid>(Windows)。文件权限必须是 640(Linux)或仅 Administrator 可读写(Windows),否则 Oracle 启动时会静默忽略它。
- 检查密码文件是否存在:
ls -l $ORACLE_HOME/dbs/orapw*(Linux)或dir %ORACLE_HOME%\database\pwd*.ora(Windows) - 重建密码文件用
orapwd file=$ORACLE_HOME/dbs/orapw$ORACLE_SID password=xxx entries=10 force=y,注意force=y覆盖旧文件 - 确认数据库参数
REMOTE_LOGIN_PASSWORDFILE是EXCLUSIVE(允许多个 SYSDBA 用户)或SHARED(仅限 SYS),不能是NONE
容器数据库(CDB)下,PDB 权限要单独处理
在 12c+ 的 CDB 架构中,GRANT CREATE SESSION TO user1; 在 CDB$ROOT 执行,只对 root 有效;想让 user1 登进某个 PDB,必须切到那个 PDB 里再授一次权限,或用 common user(用户名带 C## 前缀)并加 CONTAINER=ALL。
常见错误是:在 CDB$ROOT 里给用户授了 CREATE SESSION,结果连 PDB 时报 ORA-01031。这是因为 PDB 有自己的数据字典,权限不继承。
- 切换到目标 PDB:
ALTER SESSION SET CONTAINER = pdb1;,再执行GRANT CREATE SESSION TO app_user; - 如果要用 common user,创建时加
CONTAINER=ALL,授权也要显式写GRANT CREATE SESSION TO c##app_user CONTAINER=ALL; - PDB 中禁用 local undo 时,某些权限行为异常,建议保持
ALTER DATABASE LOCAL UNDO ON;
最常被跳过的检查点:用户账户是否被锁(ACCOUNT_STATUS 是 LOCKED 或 EXPIRED & LOCKED),以及密码策略是否触发了强制重置(ORA-28001: the password has expired 有时会伪装成 ORA-01031)。这两项不报具体错误码,但连不上就是连不上。










