只能用LOGON触发器实现单用户连接数限制,因其在认证成功后、会话启用前介入,可查询sys.dm_exec_sessions并用ROLLBACK中断超限连接。

不能用普通 DML 或 DDL 触发器实现单用户连接数限制——必须用登录触发器(LOGON trigger),且需配合系统视图和显式拒绝逻辑。
为什么只能用 LOGON 触发器
连接建立发生在会话初始化阶段,此时尚未进入任何数据库上下文,DML(如 INSERT)或 DDL(如 CREATE TABLE)触发器根本不会被调用。只有 LOGON 事件能在认证成功后、会话正式启用前介入。
-
LOGON触发器运行在服务器级别,作用于所有登录尝试 - 它能访问
sys.dm_exec_sessions获取当前已存在的同用户会话 - 若检测到超出阈值,可直接执行
ROLLBACK中断连接(注意:不能用RAISERROR后继续,必须回滚) - 其他类型触发器(比如想在
master库建个表记录连接再查)既无权限保障,也无执行时机
如何写一个有效的连接数限制触发器
核心是:查询当前登录名的活跃会话数,超过阈值就 ROLLBACK。示例限制为 3 个并发连接:
CREATE TRIGGER limit_user_logons
ON ALL SERVER
FOR LOGON
AS
BEGIN
DECLARE @login_name sysname = ORIGINAL_LOGIN();
DECLARE @session_count INT;
<pre class='brush:php;toolbar:false;'>SELECT @session_count = COUNT(*)
FROM sys.dm_exec_sessions
WHERE is_user_process = 1
AND original_login_name = @login_name
AND session_id > 50; -- 排除系统会话
IF @session_count > 3
ROLLBACK; -- 必须 rollback,否则连接仍会建立END;
-
ORIGINAL_LOGIN()获取实际登录名(不受EXECUTE AS影响) -
session_id > 50是安全过滤,避免把后台任务算进去 - 不要在触发器里做
WAITFOR或复杂计算——登录触发器必须快,否则拖慢所有连接 - 该触发器对 Windows 登录名、SQL 登录名均有效,但注意 Windows 组登录需展开成员(不推荐用于组)
容易踩的坑
这个功能看似简单,实操中几个关键点常被忽略:
- 触发器本身需要
CONTROL SERVER权限创建,普通db_owner不行 -
sys.dm_exec_sessions是动态管理视图,需VIEW SERVER STATE权限——但登录触发器内默认有该权限,无需额外授权 - 如果用了
ALTER DATABASE ... SET RECURSIVE_TRIGGERS OFF,不影响LOGON触发器,它独立于数据库设置 - 测试时别用
sa或 Windows 管理员账户——它们可能绕过资源调控;应新建 SQL 登录并单独测试 - 触发器启用后,错误不会返回详细信息给客户端,只会看到类似 “Login failed for user 'xxx'” 的通用提示,排查得查
sys.dm_exec_sessions和 SQL Server 错误日志
真正难的不是写那几行代码,而是确认 ORIGINAL_LOGIN() 和 sys.dm_exec_sessions 在你 SQL Server 版本中行为一致,并且在高并发下不会因视图延迟导致漏判或多判——这需要压测验证,不是建完就完事。

















