如何创建拥有CREATE USER权限但无法访问新数据库的MySQL用户?
如何创建拥有CREATE USER权限但无法访问新数据库的MySQL用户
这个需求的核心是权限最小化——既要让用户能创建其他用户并分配指定权限,又要严格限制它自身的数据库访问能力。下面分MySQL版本给出具体方案:
一、MySQL 8.0及以上(推荐用角色实现)
MySQL 8.0引入的角色功能可以完美分离「权限拥有」和「权限使用」,是最优雅的解决方案:
步骤1:创建用于转授的角色
先定义两个角色,分别对应给write_user分配的权限:
-- 角色1:拥有main_db的读写权限,且可以转授给其他用户 CREATE ROLE 'main_db_writer'@'localhost'; GRANT CREATE, UPDATE, INSERT, DELETE, SELECT ON main_db.* TO 'main_db_writer'@'localhost' WITH GRANT OPTION; -- 角色2:允许创建专属user_db并拥有该库的全部权限 CREATE ROLE 'user_db_creator'@'localhost'; GRANT CREATE DATABASE ON *.* TO 'user_db_creator'@'localhost'; GRANT ALL PRIVILEGES ON `user\_db\_%`.* TO 'user_db_creator'@'localhost' WITH GRANT OPTION;
步骤2:创建受限的admin用户
创建limited_admin,只给它必要的权限,且默认不激活角色:
-- 创建用户 CREATE USER 'limited_admin'@'localhost' IDENTIFIED BY '你的安全密码'; -- 授予创建用户的权限 GRANT CREATE USER ON *.* TO 'limited_admin'@'localhost'; -- 允许它转授上述两个角色,但不给它自身使用角色的权限 GRANT 'main_db_writer'@'localhost', 'user_db_creator'@'localhost' TO 'limited_admin'@'localhost' WITH GRANT OPTION; -- 关键:设置默认不激活角色,确保它自身无法使用角色的权限 SET DEFAULT ROLE NONE TO 'limited_admin'@'localhost';
效果验证
limited_admin可以:
- 创建新的write_user
- 将
main_db_writer和user_db_creator角色授予write_user
但自身无法访问main_db或任何新创建的user_db,也不能直接创建数据库(只能通过转授角色让其他人创建)。
二、MySQL 5.x(无角色,用存储过程实现)
旧版本没有角色功能,我们可以用存储过程封装创建用户和授权的逻辑,让limited_admin只能通过调用存储过程完成操作:
步骤1:创建存储过程(用root用户执行)
DELIMITER // CREATE PROCEDURE create_authorized_write_user( IN username VARCHAR(100), IN host VARCHAR(100), IN password VARCHAR(255) ) BEGIN -- 创建write_user SET @create_sql = CONCAT('CREATE USER ''', username, '''@''', host, ''' IDENTIFIED BY ''', password, ''';'); PREPARE stmt FROM @create_sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 授予main_db的读写权限 SET @grant_main_sql = CONCAT('GRANT CREATE, UPDATE, INSERT, DELETE, SELECT ON main_db.* TO ''', username, '''@''', host, ''';'); PREPARE stmt FROM @grant_main_sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 授予创建专属user_db的权限 SET @grant_user_db_sql = CONCAT('GRANT CREATE DATABASE ON *.* TO ''', username, '''@''', host, ''';'); PREPARE stmt FROM @grant_user_db_sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 授予专属user_db的全部权限 SET @grant_user_db_all_sql = CONCAT('GRANT ALL PRIVILEGES ON `', username, '_db`.* TO ''', username, '''@''', host, ''';'); PREPARE stmt FROM @grant_user_db_all_sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END // DELIMITER ;
步骤2:给limited_admin授权
-- 创建用户 CREATE USER 'limited_admin'@'localhost' IDENTIFIED BY '你的安全密码'; -- 只允许它调用这个存储过程,不给任何其他权限 GRANT EXECUTE ON PROCEDURE create_authorized_write_user TO 'limited_admin'@'localhost';
效果验证
limited_admin只能通过调用存储过程创建符合要求的write_user,自身没有任何数据库访问权限,也不能直接创建其他用户或分配额外权限。
关键注意事项
- 绝对避免全局WITH GRANT OPTION:全局的
WITH GRANT OPTION会让用户获得所有数据库的权限,完全违背需求,一定要把权限范围限制在特定数据库或角色上。 - 权限最小化:只给
limited_admin完成工作必需的权限,不要多给。 - 测试权限边界:创建后一定要测试:
- 尝试访问
main_db:应该被拒绝 - 尝试创建用户并分配指定权限:应该成功
- 尝试分配超出范围的权限(比如DROP数据库):应该被拒绝
- 尝试访问
内容的提问来源于stack exchange,提问作者iWizard




