含@database_user_name的SQL作业运行权限错误排查与解决
问题描述
- 已创建指定
@database_user_name的SQL Server代理作业,作业中指定的数据库用户testloginuser拥有目标数据库AdventureWorks2019的db_owner角色,对应的登录账号TestLogin具备sysadmin服务器角色 - 作业执行失败,报错信息:
以用户intuser执行。用户无执行此操作的权限。[SQLSTATE 42000] (错误297)。步骤失败。
- 故障发生在调用
msdb.dbo.syscategories表或执行DBCC SQLPERF(logspace)命令的环节
作业脚本示例
USE [msdb] GO BEGIN TRANSACTION DECLARE @ReturnCode INT SELECT @ReturnCode = 0 IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1) BEGIN EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]' IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback END DECLARE @jobId BINARY(16) EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'SQLdbjob', @enabled=1, @notify_level_eventlog=0, @notify_level_email=0, @notify_level_netsend=0, @notify_level_page=0, @delete_level=0, @description=N'No description available.', @category_name=N'[Uncategorized (Local)]', @owner_login_name=N'TestLogin', @job_id = @jobId OUTPUT IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Verify.', @step_id=1, @cmdexec_success_code=0, @on_success_action=1, @on_success_step_id=0, @on_fail_action=1, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=' exec InsertspSQLPerf', @database_name=N'AdventureWorks2019', @database_user_name='testloginuser', @flags=0 IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1 IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'syspolicy_purge_history_schedule', @enabled=1, @freq_type=4, @freq_interval=1, @freq_subday_type=1, @freq_subday_interval=0, @freq_relative_interval=0, @freq_recurrence_factor=0, @active_start_date=20080101, @active_end_date=99991231, @active_start_time=20000, @active_end_time=235959, @schedule_uid=N'e63973f1-0bee-4097-962f-b5d1ec12adb4' IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)' IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback COMMIT TRANSACTION GOTO EndSave QuitWithRollback: IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION EndSave: GO
原因排查
- 执行上下文冲突:作业步骤指定了
@database_user_name='testloginuser',但报错显示作业以intuser执行,说明SQL Server代理的默认启动账户覆盖了指定的执行上下文——若作业步骤未明确绑定有权限的代理账户,会默认使用代理服务的启动账户(intuser),而非作业所有者或指定的数据库用户。 - 权限范围不匹配:
db_owner仅为数据库级角色,无法访问msdb系统数据库对象或执行服务器级的DBCC命令;- 即使登录账号是
sysadmin,指定@database_user_name后,执行上下文会切换为该数据库用户,此时服务器角色权限不会生效,仅使用数据库用户的权限。
解决办法
方法1:移除数据库用户指定,使用作业所有者权限
修改作业步骤的创建脚本,移除@database_user_name='testloginuser'参数,让作业以具备sysadmin权限的作业所有者TestLogin身份执行,直接继承服务器级权限访问msdb对象和执行DBCC命令。
方法2:为数据库用户补充跨库/服务器级权限
如果必须保留@database_user_name的指定,执行以下操作:
- 在
msdb数据库中映射testloginuser并授予读取权限:USE msdb GO CREATE USER testloginuser FOR LOGIN TestLogin GO GRANT SELECT ON msdb.dbo.syscategories TO testloginuser - 为登录账号授予执行
DBCC SQLPERF(logspace)所需的服务器级权限:GRANT VIEW SERVER STATE TO TestLogin
方法3:使用权限匹配的代理账户
创建具备sysadmin权限的SQL Server代理账户,在作业步骤中指定使用该代理账户执行,确保执行上下文拥有访问所有资源的权限。
内容的提问来源于stack exchange,提问作者Narendra
相关产品推荐
相关产品推荐

