sql server中授execute权限须指定完整三段式名称(如object::[sales].[usp_getordersummary])、确保用户已在目标库创建、权限仅限当前数据库,且默认所有权链可自动校验底层对象访问。

直接给用户授予 EXECUTE 权限即可,不需要额外给表或架构权限——只要存储过程本身不显式绕过所有权链(比如用动态 SQL 拼接表名并执行),SQL Server 默认会通过“所有权链”自动验证底层对象访问合法性。
GRANT EXECUTE ON 语句必须带完整三段式名称
很多人在执行 GRANT EXECUTE 时只写存储过程名,结果报错 The server principal "xxx" is not able to access the database "yyy" under the current security context 或权限不生效。根本原因是没指定 schema,SQL Server 默认找 dbo,但如果你的存储过程在 sales 或 hr schema 下,就必须显式写出:
GRANT EXECUTE ON OBJECT::[sales].[usp_GetOrderSummary] TO [app_user];- 不能简写成
GRANT EXECUTE ON usp_GetOrderSummary TO [app_user];(可能失败) - 也不能漏掉
OBJECT::前缀——虽然某些版本容忍省略,但在 SQL Server 2016+ 及严格模式下推荐始终带上,避免和旧版语法混淆
用户必须已存在于目标数据库中,不是仅建了登录名
常见错误是只运行了 CREATE LOGIN [app_user] WITH PASSWORD = '...';,就直接授存储过程权限,结果提示 Cannot find the user 'app_user', because it does not exist or you do not have permission.。这是因为登录(Login)是实例级,用户(User)是数据库级,必须先在目标库内创建用户:
- 先切换到目标数据库:
USE [YourDB]; - 再创建数据库用户:
CREATE USER [app_user] FOR LOGIN [app_user]; - 如果登录名和用户名不同(比如登录叫
sql_app_login,用户叫app_user),要写成:CREATE USER [app_user] FOR LOGIN [sql_app_login];
验证权限是否生效,别只靠“没报错”就认为成功
授完权后立刻用 EXECUTE AS USER 测试最可靠。光看 GRANT 语句执行成功,不代表用户真能跑通——比如存储过程里查了另一张用户没权限的表,或用了 EXEC sp_executesql 动态访问对象,都会在运行时报错,而非授权时报错:
- 测试命令示例:
EXECUTE AS USER = 'app_user'; EXEC [sales].[usp_GetOrderSummary]; REVERT; - 如果报
The SELECT permission was denied on the object 'Orders', database 'YourDB', schema 'sales',说明过程内部访问了未授权表,所有权链断裂 - 此时要么补授权(
GRANT SELECT ON [sales].[Orders] TO [app_user]),要么改写存储过程避免跨 schema 引用,或用EXECUTE AS OWNER保证上下文一致
最容易被忽略的一点:权限只作用于当前数据库。哪怕你在 master 里给用户授了某个存储过程权限,它在 AdventureWorks 里照样不能执行——每个数据库的用户和权限都是独立维护的。











