能。LOGON触发器可通过查询sys.dm_exec_sessions统计目标账号活跃会话数(需排除当前session_id @@SPID、限定status为running/sleeping、使用original_login_name),并在超限时执行ROLLBACK中断登录,从而实现并发连接数限制。

LOGON触发器能直接限制并发连接数吗?
不能。SQL Server 的 LOGON 触发器本身不提供“拒绝第N个连接”的原生能力,它只能在登录认证成功后、会话建立前执行逻辑,并通过 ROLLBACK 中断本次登录。真正实现“限制并发数”,必须靠你自己查当前会话数并做判断——而这个查询必须快、准、避开自身会话干扰。
怎么写一个可靠的并发数检查逻辑?
关键在于用 sys.dm_exec_sessions 精确统计目标账号的活跃会话,同时排除当前正在触发的会话(它还没被计入该 DMV)。常见错误是直接 COUNT(*) 所有匹配 login_name 的行,结果把自己也算进去,导致永远卡在 N−1 个连接就拒绝后续登录。
- 必须加条件
session_id @@SPID排除当前触发会话 - 推荐用
original_login_name而非login_name,避免代理登录(如 Windows 组成员)误判 - 检查范围限定为
status = 'running' OR status = 'sleeping',忽略preconnect等无效状态 - 示例片段:
DECLARE @cnt INT; SELECT @cnt = COUNT(*) FROM sys.dm_exec_sessions WHERE original_login_name = EVENTDATA().value('(/EVENT_INSTANCE/LoginName)[1]', 'sysname') AND session_id <> @@SPID AND status IN ('running', 'sleeping'); <p>IF @cnt >= 3 -- 允许最多3个并发 ROLLBACK;
为什么上线后有时仍出现“超限但没拦住”?
根本原因是 sys.dm_exec_sessions 的可见性延迟和事务隔离问题。LOGON 触发器运行在自己的事务中,而新会话在触发器提交前尚未完全注册进 DMV;更隐蔽的是,某些客户端(如 SSMS 新建查询窗口)会在登录后立刻发一条空闲语句(SELECT NULL),造成短暂的 running 状态,干扰计数。
- 不要依赖
last_request_end_time或心跳时间做过滤——太不可靠 - 若业务允许,把阈值设为 N−1 并加一点余量(比如想控 3 个,代码里写 >= 2)
- 务必在触发器开头加
SET NOCOUNT ON,避免客户端误将消息当结果集解析失败 - 测试时用
sqlcmd -S server -U user -P pwd多开终端,比 SSMS 更干净
权限与部署要注意哪些硬性约束?
LOGON 触发器必须由 sysadmin 创建,且数据库需启用 TRUSTWORTHY(不推荐)或使用证书签名(推荐)。最常踩的坑是:DBA 用 sa 创建了触发器,但忘记给目标账号授予 VIEW SERVER STATE 权限——触发器内部查 dm_exec_sessions 就会静默失败,然后放行所有连接。
- 必须显式执行:
GRANT VIEW SERVER STATE TO [YourLogin];
- 触发器本身不能包含跨库引用(如
otherdb.sys.dm_exec_sessions),会报错 - 修改触发器后需用
DISABLE TRIGGER ... ON ALL SERVER+ENABLE才生效,ALTER不够
实际生效前,一定用不同账号反复压测到临界点——并发控制这种事,差一个会话就等于没控住。

















