|
MySQL有一个先进但非标准的安全/权限系统。本文描述它的工作原理。 9 J g8 ` M) g& K: @
" p' V5 t0 V, V
权限系统做什么 ) z. R/ v5 u) @
MySQL权限系统的主要功能是证实连接到一台给定主机的一个用户,
* m6 \" i/ P& c: b2 ^: W, S- \并且赋予该用户在一个数据库上select、 insert、update和delete的 & r; u5 _1 K- e/ Z* w) s0 b
权限。
: _, U% S% z8 q& q/ k/ A( J4 k
附加的功能包括有一个匿名的用户和对于MySQL特定的功能例如 8 q$ X% R- v3 L6 R- u3 Q' V- ^
LOAD DATA INFILE进行授权及管理操作的能力。 " V0 i+ B5 Z% I: T* h0 p
0 r- R* K& A' ]3 J5 X/ m' jMySQL 用户名和口令 : j& W, ?- u, v: T9 k1 d+ H m
由MySQL使用用户名和口令的方法与Unix或Windows使用的方式有很 $ x3 C$ W l! M
多不同之处: ' E' z- }. f! K. o
. W v4 W ?, q- w; |0 uMySQL使用于认证目的的用户名,与Unix用户名(登录名字)或
9 u- B# ^$ G: C: ]Windows用户名无关。缺省地,大多数MySQL客户尝试使用当前Unix用户 7 ^ [" F; J" P% e# M
名作为MySQL用户名登录,但是这仅仅为了方便。客户程序允许用-u或- - ~3 g& G& x. W6 Q8 X% _1 p/ C
-user选项指定一个不同的名字,这意味着无论如何你不能使得一个数据 " X0 ]0 I: l9 y% ^9 x5 c) ^
库更安全,除非所有的MySQL用户名都有口令。任何人可以试图用任何名
: X, V; x; T, N9 ~7 |( U1 p字连接服务器,而且如果他们指定了没有口令的任何名字,他们将成功。 # E: W& n' J! _6 E3 Z
MySQL用户名最长可以是16各字符;典型地,Unix用户名限制为8个字符。
# |3 R" K* ^- T# A- SMySQL口令与Unix口令没关系。在你使用登录到一台Unix机器口令和你使 / v, H$ x( @5 B1 f X
用在那台机器上存取一个数据库的口令之间没有必要有关联。
3 J5 t6 R; s& u) SMySQL加密口令使用了一个Unix登录期间所用的不同算法。
; b0 l3 \- F' ]) e+ {" V! W* D% U B2 Z! j& J
与MySQL服务器连接 7 e9 Q/ j' t* v- e8 ]
当你想要存取一个MySQL服务器时,MySQL客户程序一般要求你指定
' J9 a$ ^6 H+ ?/ I2 }% ^2 o0 V连接参数:你想要联接的主机、你的用户名和你的口令。例如,mysql
! ]6 b2 Z) R5 v" Q" X( W: b- r客户可以象这样启动(可选的参数被包括在“[”和“]”之间): , J/ L' P! s, \: i- w$ p
, _5 @# A. C7 X3 C2 ?: |shell> mysql [-h host_name][-u user_name][-pyour_pass ] % a. {/ e" ~) R' p3 O2 v) B
-h, -u和-p选项的另一种形式是--host=host_name、--user= ; \, |1 A* M5 r, X1 V
user_name和--password=your_pass。注意在-p或--password=与跟随它 & N! b5 m- E+ u& `! d, \0 A" U* I- {
后面的口令之间没有空格。 ' k. w% T( K/ H! i8 u
+ I, A6 r/ p, B2 @/ ?
注意:在命令行上指定一个口令是不安全的!随后在你系统上的任
( k, ~# M& e; Y1 V4 o何用户可以通过打类似这样的命令发现你的口令:ps auxww。 ; w* ]) z9 J4 f; s, m5 \
2 ]! W! `5 I* Q9 v; I8 A, |4 _& l h
对于命令行没有的联接参数,mysql使用缺省值:
9 `5 W& P8 i U
/ _* q5 P, w0 W2 \* o1 a4 j8 c1 ?缺省主机名是localhost。
' @" Y' F0 F" _; E! r# @% U1 R缺省用户名是你的Unix登录名。
! B) z; a# |' ^! o8 J. b- _7 \如果没有-p,则没有提供口令。
7 d0 I7 P f: y8 d这样, 对一个Unix用户joe,下列命令是等价的: ' Z ~$ P% p* g/ U" x R
' g" x- B; c* \" a+ ashell>mysql -h localhost -u joe ! J0 T! ~" J3 q# y) c* _2 N
shell>mysql -h localhost
! k: R6 ]- L0 l1 }shell>mysql -u joe
/ m1 a( E0 v; B0 n/ L, t! ^0 kshell>mysql
: q- `2 S5 ]$ g# X3 a7 B" v9 M# I' ~6 N
其它MySQL客户程序有同样表现。
- f6 l! r" b* u
( J" R* d1 L4 ~' o9 a; E4 y在Unix系统上,当你进行一个连接时,你可以指定要使用的不同的缺 , s3 _6 A4 N% h# @3 e& L; z7 Y
省值,这样你不必每次在你调用一个客户程序是在命令行上输入他们。这 : s) n6 y2 n# k. \2 ]& T2 q
可以有很多方法做到: & g+ ^1 y. x0 M7 B S3 @( y
5 w. x5 T [9 H& N6 e6 n+ X+ f你能在你的主目录下“.my.cnf”的配置文件的[client]小节里指定
0 g9 q, z3 T% m, `" J5 o2 m连接参数。文件的相关小节看上去可能像这样: ' _) i: u w$ q: F
[client] 9 |3 {+ D/ v8 s! z& R
host=host_name
7 f" ~0 ~$ i$ a! ]8 N) q$ d T5 puser=user_name
& f7 `0 y m) k/ s- m) Epassword=your_pass ' r) q; h( e( Z0 ^! |8 a
: [. R3 ^1 @( T2 y9 q! H' d0 [7 x你可以用环境变量指定连接参数。主机可用MYSQL_HOST指定,MySQL
* Z0 I# P9 s5 E. a/ K7 P用户名字可用USER指定(仅对 Windows),口令可用MYSQL_PWD指定(但是 ! M( B9 Q0 |' O# u. e
这不安全) 。 0 u! ~1 v2 m. A! |- {* E
如果连接参数以多种方法被指定,在命令行上被指定的值优先于在配
, k; u6 e( Y7 I置文件和环境变量中指定的值,而在配置文件指定的值优先于在环境变量
& M3 b1 d* P' Z4 J6 E6 M指定的值。
+ }, \. W+ r# B2 B8 ?4 I& o8 T0 T8 S0 d( \: q
使你的口令安全
; A! f2 q6 T* H g' L以一种暴露的可被其他用户发现的方式指定你的口令是不妥当的。 ; v4 h+ [! R4 g! K: w# ?
当你运行客户程序时,你可以使用下列方法指定你的口令,还有每个方法
2 H* _# E3 P& |7 V& d& X8 D5 Z+ E% i的风险评估:
" V( N2 H* [; b2 ?9 j* @8 P
! y) O$ G7 L! _6 l }1 J使用一个在命令行上-pyour_pass或--password=your_pass的选项。
4 E; v" |' E9 Q/ D4 S6 l; E* B* _这很方便但是不安全,因为你的口令对系统状态程序(例如ps)变得可见, 2 |9 e2 [) {. J" \
它可以被其他的用户调用来显示命令行。(一般MySQL客户在他们的初始化
) l: x7 j( i5 k0 _- `% i% A5 y顺序期间用零覆盖命令行参数,但是仍然有一个短暂间隔时间内参数值可 2 Z. n2 g4 ~; Y# w8 R
见的。) ! Z+ r; t3 X; {# c' x0 Z
使用一个-p或--password选项(没有指定your_pass值)。在这种情况 3 h1 O4 y9 ?2 |3 c
下,客户程序请求来自终端的口令: 9 u- k6 g7 _' p: j& d# d* b" E
9 J# I; f/ C% n, ?2 w% qshell>mysql - u user_name - p 2 p: F( s) w) x: H
Enter password: ******** 1 @/ F' L8 ]8 M% h/ ~
- M! I' \& b) }/ H
客户回应“*”字符到作为输入你的口令的终端使得旁观者不能看见 6 p- A0 X! @4 s6 b( i/ v- T
它。因为它对其他用户不可见,与在命令行上指定它相比,这样进入你 0 l0 U- y6 V( Q: w5 F$ l
的口令更安全。然而,这个输入一个口令的方法仅仅为你交互式运行程
3 M7 G8 G' K( p序是合适的。如果你想要从非交互式运行的一个脚本调用一个客户,就
8 Y: c/ p) [7 c没有从终端输入入口令的机会。
# l# F3 z" m- O! a2 i+ A/ w! M, S0 r" W' |0 D" k ?
在一个配置文件中存储你的口令。例如,你可你的主目录的 , F( q' i6 G) t; A2 Y; p# \
“.my.cnf”文件中的[client]节列出你的口令: $ u: E& ?& Z: C! k
[client]
- N/ W: j! D. x6 M( t& n9 apassword=your_pass # ? x% k0 S, Z& b
# g) N( P. q$ j/ [
如果你在“.my.cnf”里面存储口令,文件应该不是组或世界可读或 " p- P7 ?: M$ g( J$ x* @8 d
可写的。保证文件的存取模式是400或600。见4.15.4 选项文件。 ! V& [; w3 C/ [' j4 \2 {, v
4 G1 _* z( g$ h7 d你可在MYSQL_PWD环境变量中存储口令,但是这个方法必须想到是极
3 X* _1 M( H) F+ i+ z( \ {8 ]& p不安全的且应该不使用。ps的某些版本包括显示运行进程的环境的选项; : K$ ?3 e1 S8 E% l
如果你设定MYSQL_PWD,你的口令将对所有人是显而易见的,甚至在没有 3 e; B3 ~5 ?9 u
这样一个版本的ps系统上,假设没有其他方法观察到进程环境是不明智
$ @! ~ V E# c7 o# |; Q的。
' u$ M7 d$ h+ d/ _- s总之,最安全的方法是让客户程序提示口令或在一个适当保护的“ 6 R( c U8 |5 A2 Y+ s9 q) b( x. h
.my.cnf”文件中指定口令。
5 D6 O: g0 M' j. D
4 D( V9 Q8 Y& X: c9 V8 w1 d# hMySQL提供的权限 ( Y& @. W& n3 b+ n" J( F' _& {
权限信息用user、db、host、tables_priv和columns_priv表被存储 5 m+ E* z. r$ Q2 u# W
在mysql数据库中(即在名为mysql的数据库中)。在MySQL启动时和在权限
, ?8 w$ u2 J8 X, }% p修改何时生效所说的情况时,服务器读入这些数据库表内容。
# t; ` h4 C, p ]3 G* x
; M+ _, ]! ^2 e) b' [ U由MySQL提供的权限名称显示在下表,还有在授权表中每个权限的表 , a4 f3 _5 ?1 `; J" y v' ~
列名称和每个权限有关的上下文:
5 {2 n# M# C8 b0 m9 g权限 列 上下文 select Select_priv 表 insert Insert_priv 表 update Update_priv 表 delete Delete_priv 表 index Index_priv 表 alter Alter_priv 表 create Create_priv 数据库、表或索引 drop Drop_priv 数据库或表 grant Grant_priv 数据库或表 references References_priv 数据库或表 reload Reload_priv 服务器管理 shutdown Shutdown_priv 服务器管理 process Process_priv 服务器管理 file File_priv 在服务器上的文件存取 8 p" S0 ?) B$ p. Z& Z$ W* `
select、insert、update和delete权限允许你在一个数据库现有的 + \& w( K$ O8 A9 }/ s0 R$ L& i1 P
表上实施操作。 3 F4 v a9 p, y' ?8 z: W9 K' i
/ l) F# e# X6 ^' KSELECT语句只有在他们真正从一个表中检索行是才需要select权限, 4 P3 ^! _. N- v; {7 [7 U5 H7 }
你可以执行某个SELECT语句,甚至没有任何到服务器上的数据库里的存
O# ?! Q& B" a4 D$ m取任何东西的许可。例如,你可使用mysql客户作为一个简单的计算器: , c1 U1 p9 V- Y: o3 ~2 H9 ` B
! k" L0 w; s+ n4 M
mysql> SELECT 1+1; 1 s% I# p9 p5 o' h, Q" ~; k" ~& z3 ]
mysql> SELECT PI()*2;
1 Z- g3 E- e# o/ A3 i6 ~, F" v! o' e) \( x
index权限允许你创建或抛弃(删除)索引。 T% V1 w: J1 V( u4 f9 D( s* I
9 e/ s* X* ]8 ?2 |$ balter权限允许你使用ALTER TABLE。 9 b0 x2 i, [) R) o) L; G! J4 H1 j
: p2 R# _) c6 G9 t
create和drop权限允许你创建新的数据库和表,或抛弃(删除)现存的 / A, C. ~- j' k7 k
数据库和表。 \6 G3 g- t& V+ ~0 k# {. r( a4 a
& o8 d P. f; D# e9 F0 M ]注意:如果你将mysql数据库的drop权限授予一个用户,该用户能抛弃 9 z2 R$ L! `) K% Z9 P7 p" E
存储了MySQL存取权限的数据库! - _2 J: y9 Z$ |: G
' U. l3 {+ b7 ]! z7 rgrant权限允许你把你自己拥有的那些权限授给其他的用户。 / Z w8 U, Q5 h( ?
6 q! h. }5 Y# J
file权限给予你用LOAD DATA INFILE和SELECT ... INTO OUTFILE语句 # [" Q3 q: ]1 E; V2 k
读和写服务器上的文件,任何被授予这个权限的用户都能读或写MySQL服务 9 Z+ z8 n: T* [; R& V3 [, i! N
器能读或写的任何文件。 , g4 y& Y. b! |
0 Q/ k- j' M, u+ Z
其余的权限用于管理性操作,它使用mysqladmin程序实施。下表显示 6 d9 x5 e1 h+ Z# i+ r
mysqladmin支配每个管理性权限允许你执行的命令:
- O2 n7 m* Z7 b5 z! L6 {# s优惠 权限拥有者允许执行的命令 reload reload, refresh, flush-privileges, flush-hosts, flush-logs, flush-tables shutdown shutdown precess processlist, kill 4 g b) t5 H4 n
reload命令告诉服务器再读入授权表,refresh命令清洗所有表并打开 # \: R. Z' `7 c, N' h) w
和关闭记录文件,flush-privileges是reload的一个同义词,其它flush-* * v& V2 ^9 }; h4 B" s- b8 x7 m1 g
命令执行类似refresh的功能,但是范围更有限,并且在某些情况下可能更
! E& N3 y. l* g& N' m0 V! q好用。例如,如果你只是想清洗记录文件,flush-logs比refresh是更好的 3 z$ x T+ j$ p5 W
选择。 % }- V8 C/ ]' U
6 b9 t) T* Q( w# l4 ?shutdown命令关掉服务器。
" X9 v6 o* N, s v; O
4 O8 a% e2 i; e( M( x% Aprocesslist命令显示在服务器内执行的线程的信息。kill命令杀死服
) W! f; E+ v: ]务器线程。你总是能显示或杀死你自己的线程,但是你需要process权限来 % v h0 [/ x# [2 [$ ]9 S3 h
显示或杀死其他用户启动的线程。
# A! M4 u$ e: f& e, S" L1 Z! U7 A, Q4 m: Z7 ^( A8 u
总的说来,只授予权限给需要他们的那些用户是一个好主意,但是你
: T; z+ G s: ~; W6 @2 t- [1 H( i应该在授予某个权限时试验特定的警告: / S3 g8 j8 L! u3 V3 T& r9 }& c
& A6 T* g: |- E% {9 r$ F9 _6 Rgrant权限允许用户放弃他们的权限给其他用户。2个有不同的权限并
- y+ d% i9 _# q. O8 O) u5 U有grant权限的用户可以合并权限。 ' g5 ? o% s1 o M! ~' x& X1 w2 E
alter权限可以用于通过重新命名表来推翻权限系统。
" W# p Z4 U5 S( Y2 dfile权限可以被滥用在服务器上读取任何世界可读(world-readable, # l B( }% N, S
即任何人可读)的文件到一张数据库表,然后其内容能用SELECT被存取。
1 R0 }7 I+ `3 |shutdown权限通过终止服务器可以被滥用完全拒绝为其他用户服务。
2 S5 b1 ~) e* C% l, \) {/ f" h5 Jprecess权限能被用来察看当前执行的查询的普通文本,包括设定或改 7 A+ b0 S% T- j# f7 M
变口令查询。 ! o% c$ v5 O! H! b
在mysql数据库上的权限能被用来改变口令和其他存取权限信息。(口 ! B( Y0 Y' {( H% c2 u/ X
令被加密存储,所以一个恶意的用户不能简单地读取他们。然而,有足够 ' l# C% A; T* Q
的权限,同一个用户能用不同的一个代替一个口令。)
- A8 d4 u j) b, f+ E( ^有一些事情你不能用MySQL权限系统做到: - u0 T. y. c# N
" X( }/ w8 v( [# W! {. _ x! ]! {你不能明显地指定一个给定用户应该被拒绝存取。即,你不能明显地匹
! @+ D- Q9 D: D( k配一个用户并且然后拒绝连接。 $ k+ u& J6 k* @" w( i
你不能指定一个用户有权创建立或抛弃一个数据库中的表,也不能创建 3 n# C8 W6 ]$ w# N7 Z
或抛弃数据库本身。 6 T0 p1 q+ q# q( J
权限系统工作原理 $ A4 X; i ` k/ e \" `
MySQL权限系统保证所有的用户可以严格地做他们假定被允许做的事情。
: Y: e( U4 H# P当你连接一个MySQL服务器时, 你的身份由你从那连接的主机和你指定的用
* s1 T7 Z( f3 a3 X; O' s! H1 F户名来决定,系统根据你的身份和你想做什么来授予权限。
- w6 m$ A7 T5 I) f
; k, @! p( A, _3 B2 U: [9 ^' k( ?MySQL在认定身份中考虑你的主机名和用户名字,是因为有很小的原因假 + U% _" c# B4 ]
定一个给定的用户在因特网上属于同一个人。例如,用户从whitehouse.gov + y @) r" M3 K8 k
连接的bill不必和从mosoft.com连接bill是同一个人。 MySQL通过允许你区
% ?" L" v: i: b" p分在不同的主机上碰巧有同样名字用户来处理它:你可以对从whitehouse.gov , O# {1 M; H' N! H4 _9 [
连接授与bill一个权限集,而为从microsoft.com的连接授予一个不同的权限
1 Q0 v: d: t% `* G8 [集。
* \3 t1 }, j9 D, A+ N: K0 B7 w O) _0 w
MySQL存取控制包含2个阶段:
- u, V5 I1 ?& E5 E
# h. `! \4 E3 m7 L, ]3 e( v4 |阶段1:服务器检查你是否允许连接。 & K& w N+ ^; [0 r
阶段2:假定你能连接,服务器检查你发出的每个请求。看你是否有足够 4 }$ t0 ]4 [0 ?$ Z% V) M
的权限实施它。例如,如果你从数据库中一个表精选(select)行或从数据库抛
$ |7 J% K: a0 `: Z! @) F弃一个表,服务器确定你对表有select权限或对数据库有drop权限。 1 W; m& l; k; G* X
服务器在存取控制的两个阶段使用在mysql的数据库中的user、db和host ( f* F) C" R" g6 F) @. n& z9 t& }
表,在这些授权表中字段如下:
9 _, n# `' |5 K& x j表名称 user db host 范围字段 Host Host Host User Db Db Password User 权限字段 Select_priv Select_priv Select_priv Insert_priv Insert_priv Insert_priv Update_priv Update_priv Update_priv Delete_priv Delete_priv Delete_priv Index_priv Index_priv Index_priv Alter_priv Alter_priv Alter_priv Create_priv Create_priv Create_priv Drop_priv Drop_priv Drop_priv Grant_priv Grant_priv Grant_priv Reload_priv Shutdown_priv Process_priv File_priv 0 \3 P: }, B @9 w4 Z- ?
对存取控制的第二阶段(请求证实),如果请求涉及表,服务器可以另外
, y6 C4 r. [/ p5 E: O参考tables_priv和columns_priv表。这些表的 7 [3 n+ @/ H5 o# [2 U
字段如下: # H3 l8 X1 F) {% }( j. \
表名称 tables_priv columns_priv 范围字段 Host Host Db Db User User Table_name Table_name Column_name 权限字段 Table_priv Column_priv Column_priv 其他字段 Timestamp Timestamp Grantor
$ c5 X5 c. y2 G对存取控制的第二阶段(请求证实),如果请求涉及表,服务器可以另外 : J; g6 |8 A) \5 h
参考tables_priv和columns_priv表。这些表的字段如下: 2 s6 P6 ^* h( q( Q2 Z
字段名 类型 Host CHAR(60) User CHAR(16) Password CHAR(16) Db CHAR(64) (tables_priv和columns_priv表为CHAR(60)) ; j1 s% x$ i2 I2 k% n
在user、db和host表中, : T# w; q: U' a% W- r$ y/ o
所有权限字段被声明为ENUM('N','Y')--每一个都可有值
G3 q' j9 w; g0 S$ T'N'或'Y',并且缺省值是'N'.
4 I. f6 E7 O; R D在tables_priv和columns_priv表中,权 $ f4 f0 h [/ N; A" H! h
限字段被声明为SET字段:
6 d$ G$ D7 b/ \4 A表名 字段名 可能的集合成员 tables_priv Table_priv 'Select', 'Insert', 'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter' tables_priv Column_priv 'Select', 'Insert', 'Update', 'References' columns_priv Column_priv 'Select', 'Insert', 'Update', 'References' / X/ C7 c# E# D, `3 v& U5 Q
每个授权表包含范围字段和权限字段。
' S8 ^$ e' L; o( m" ?" r' X* T( y( J8 b, ]5 A S/ c W2 b
范围字段决定表中每个条目的范围,即,条目适用的上下文。例如, ; I+ ~- g! R b' q7 `( R6 \
一个user表条目的Host和User值为'thomas.loc.gov'和'bob'将被用于 * L$ M' p/ k9 K
证实来自主机thomas.loc.gov的bob对服务器的连接。同样,一个db表条 {; h3 P% b2 A9 [, K5 m; m0 R
目的Host、User和Db字段的值是'thomas.loc.gov'、'bob'和'reports'
) ?( F0 h5 t+ g1 O8 U5 e, n将用在bob从主机联接thomas.loc.gov存取reports数据库的时候。
& b5 W& i3 P) Y4 V# n9 s0 btables_priv和columns_priv表包含范围字段,指出每个条目适用的表或
4 P) A/ v' t: ~表/列的组合。
7 [7 j9 Q; H5 N* L, n2 q! ^1 n, E: c6 y5 x$ N
对于检查存取的用途,比较Host值是忽略大小写的。User、Password、
, s1 a$ E# @) h0 a5 X& W5 @ f. kDb和Table_name值是区分大小写的。Column_name值在MySQL3.22.12或以 6 k4 X7 X. p d" ]' E: Z7 u/ z' `
后版本是忽略大小写的。 ( ?$ P6 q" y2 P) A/ S
; z2 s+ D- @& I. B权限字段指出由一个表条目授予的权限,即,可实施什么操作。服务
% b7 u3 C. b0 E2 ^* w( _器组合各种的授权表的信息形成一个用户权限的完整描述。为此使用的规
% \ q4 u; y- F1 z% l则在6.8 存取控制, 阶段2:请求证实描述。 ( ^1 s. h' Y: K, @# A x
( n5 ]! o5 a y9 S5 {
范围字段是字符串,如下所述;每个字段的缺省值是空字符串:
6 {' p% Y) }( R9 S2 `" L字段名 类型 Host CHAR(60) User CHAR(16) Password CHAR(16) Db CHAR(64) (tables_priv和columns_priv表为CHAR(60)) . U$ [$ b9 ~, b% m! x
在user、db和host表中,所有权限字段被声明为ENUM('N','Y')--每一 0 s8 o& J, X" l7 A- U7 I P! b; `
个都可有值'N'或'Y',并且缺省值是'N'.
) U- E0 Z- Q; w" _. W$ {4 D
: b7 |0 r: |- A9 t在tables_priv和columns_priv表中,权限字段被声明为SET字段:
2 S8 w! @' w" P7 B/ R. X; u# X. u/ ]表名 字段名 可能的集合成员 tables_priv Table_priv 'Select', 'Insert', 'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter' tables_priv Column_priv 'Select', 'Insert', 'Update', 'References' columns_priv Column_priv 'Select', 'Insert', 'Update', 'References' 9 {- _: v2 x5 K0 ?4 l2 _: L
简单地说,服务器使用这样的授权表: * j# O) \( U* f5 d- U2 y
9 c. M2 |# N9 G: W. W, B/ E
user表范围字段决定是否允许或拒绝到来的连接。对于允许的连接,
' C9 W0 ~/ p3 h2 D2 u1 x( Y权限字段指出用户的全局(超级用户)权限。
# t! M$ T& h. W' ydb和host表一起使用: ' B- H& K' H0 t4 ?4 r K1 @; d, F
db表范围字段决定用户能从哪个主机存取哪个数据库。权限字段决定 ' @2 {, `$ H+ W) P5 e) V( n
允许哪个操作。
; L; L. t, B) U2 {4 I1 |当你想要一个给定的db条目应用于若干主机时,host表作为db表的扩
( a, {& R, h( n展被使用。例如,如果你想要一个用户能在你的网络从若干主机使用一个 ( Z r! R/ i4 X
数据库,在用户的db表的Host条目设为空值,然后将那些主机的每一个移
( J9 Y1 p a# Z. m, H. ~2 R入host表。这个机制详细描述在6.8 存取控制, 阶段2:请求证实。
. o- h! f* ~0 R4 c/ P; s, c1 vtables_priv和columns_priv表类似于db表,但是更精致:他们在表
! L2 X: U$ F) o: N和列级应用而非在数据库级。
4 P1 J8 h! i" b8 ^+ K: m9 r3 _& H注意管理权限(reload, shutdown, 等等)仅在user表中被指定。这是
' Y) c1 p# a Q+ Q% Y& r5 B' W因为管理性操作是服务器本身的操作并且不是特定数据库,因此没有理由
( t' U' q9 s7 V! t% O9 I. H6 k在其他授权表中列出这样的权限。事实上,只需要请教user表来决定你是 3 ?4 ]) T9 z6 h( D1 G) E! }2 L$ K
否执行一个管理操作。
. H7 a; H4 p" u/ x4 u& [& \% x8 k& K; I4 T- U( L! W
file权限也仅在user表中指定。它不是管理性权限,但你读或谢在服
- H2 `' o- g( v* w7 b2 Q, p务器主机上的文件的的能力独立于你正在存取的数据库。
+ h6 b |& A _6 j) `) ?6 d
( H9 I( r3 w) c! p' ^" N. z4 A& S- ~当mysqld服务器启动时,读取一次授权表内容。 * J, i, w! {2 B
; ^9 l4 o! A0 ]. u# A6 J当你修改授权表的内容时,确保你按你想要的方式更改权限设置是一 / P7 B& D. }! X& o/ D
个好主意。 7 p# j- y- }" ^( B4 x: M8 Y
" F0 }$ R# U& B$ k4 R
一个有用的诊断工具是mysqlaccess脚本,由Carlier Yves 提供给
, X8 E# [' I* h& N5 o: v* W& ?MySQL分发。使用--help选项调用mysqlaccess查明它怎样工作。注意:
' [5 R; D( E; j3 ]" N, `mysqlaccess仅用user、db和host表仅检查存取。它不检查表或列级权限。 . j8 W# N& S, C7 B% `' o+ a) m
, c: O/ o2 H- m5 T# X' m- t存取控制, 阶段1:连接证实 ( M7 m3 g6 f- v9 q/ E
当你试图联接一个MySQL服务器时,服务器基于你的身份和你是否能
1 \/ M; J: }- j- C通过供应正确的口令验证身份来接受或拒绝连接。如果不是,服务器完全
7 l! Z6 C" ]2 L9 u具结你的存取,否则,服务器接受连接,然后进入阶段2并且等待请求。 % R+ X' i9 Y) ^: V7 Q* g
0 ^+ M8 W3 \2 v+ ^
你的身份基于2个信息:
3 q) N' Z: y p0 \/ B6 }2 F+ P e: d& i9 j% l
你从那个主机连接
l% d) A1 o8 f你的MySQL用户名
$ V6 E. t0 G: ^/ j; U! x身份检查使用3个user表(Host, User和Password)范围字段执行。服 , c4 D- U! ?7 L. O' L; D
务器只有在一个user表条目匹配你的主机名和用户名并且你提供了正确的 8 A# `) [2 R' O3 h2 w, m( q
口令时才接受连接。
7 l# a3 }* L. r. H* N+ \; e$ l' x0 P* a
在user表范围字段可以如下被指定: $ U% w7 H5 g1 N# H# G/ O
^2 X d0 r" P8 B7 n1 O; f5 m
一个Host值可以是主机名或一个IP数字,或'localhost'指出本地主机。
# A# S) u/ I( m! C5 Y* B3 Q( R你可以在Host字段里使用通配符字符“%”和“_”。
9 E4 j7 `$ u+ t& I一个Host值'%'匹配任何主机名,一个空白Host值等价于'%'。注意这些
' X) g3 U/ c! n" o1 s# q值匹配能创建一个连接到你的服务器的任何主机! ! g# G2 L# U ^
通配符字符在User字段中不允许,但是你能指定空白的值,它匹配任何 6 L, ]2 c+ r2 [' ]. f5 J
名字。如果user表匹配到来的连接的条目有一个空白的用户名,用户被认为 $ O* B9 \" B+ Z g1 ^8 N* F
是匿名用户(没有名字的用户),而非客户实际指定的名字。这意味着一个空 3 J4 C# h/ ~5 ~( `0 f0 f) O
白的用户名被用于在连接期间的进一步的存取检查(即,在阶段2期间)。
2 Q+ _% r$ N2 P* v" A$ i* SPassword字段可以是空白的。这不意味着匹配任何口令,它意味着用户 ; c ~' V B4 \ n1 t+ k0 x0 Y
必须不指定一个口令进行连接。 # q' ~5 @3 i N! t
非空白Password值代表加密的口令。 MySQL不以任何人可以看的纯文本
7 ^" \6 J- R9 L6 @' D4 Y格式存储口令,相反,正在试图联接的一个用户提供的口令被加密(使用
( b6 p1 |* N5 X+ s' k9 V8 y7 jPASSWORD()函数),并且与存储了user表中的已经加密的版本比较。如果他
, P7 X4 B. E8 Z们匹配,口令是正确的。 * d C3 a5 {- Z1 ^. e, F7 o9 x3 k
! b$ w2 k. ?& F
下面的例子显示出各种user表中Host和User条目的值的组合如何应用于到来
5 k+ g" c6 L: X* A# Y3 H, F; w的连接: 1 ]0 r+ s4 d% ~: t6 d* R
1 J. m! _8 H7 j, q# U
Host 值 User 值 被条目匹配的连接 + T' t _3 L l. |
'thomas.loc.gov' 'fred' fred, 从thomas.loc.gov 连接
, a+ U/ k/ u; M/ J9 j; W. X'thomas.loc.gov' '' 任何用户, 从thomas.loc.gov连接
% \5 m0 ] d+ o'%' 'fred' fred, 从任何主机连接 ) D) J# k4 C, L" g6 L7 K' P
'%' '' 任何用户, 从任何主机连接
4 I$ O) X% s3 E* ?, z'%.loc.gov' 'fred' fred, 从在loc.gov域的任何主机连接
% Y# N: p T1 d& `% I* i6 g' V% M" N'x.y.%' 'fred' fred, 从x.y.net、x.y.com,x.y.edu等联接。(这或许 / V" q/ i# u L2 I# `
无用) 7 C, f) w8 z+ }* K6 p- m9 i
'144.155.166.177' 'fred' fred, 从有144.155.166.177 IP 地址的主
2 v0 C( u+ @& G. e" I机连接
: P+ V) B5 M7 P. o'144.155.166.%' 'fred' fred, 从144.155.166 C类子网的任何主机连
( e: `7 f6 x2 U6 F4 ~接 - [7 v6 ?% F0 |+ f" Z2 z0 B
* [7 h8 k8 t, j+ n9 s( e$ Q# N既然你能在Host字段使用IP通配符值(例如,'144.155.166.%'匹配在一个子 0 ^7 P% J+ a3 a1 `$ F
网上的每台主机),有可能某人可能企图探究这种能力,通过命名一台主机
& p, k. u* Q; F为144.155.166.somewhere.com。为了阻止这样的企图,MySQL不允许匹配以
$ W; y. O; C* Z4 L2 V数字和一个点起始的主机名,这样,如果你用一个命名为类似1.2.foo.com的 * I' }+ m! t2 N: a" H# P4 O- i
主机,它的名字决不会匹配授权表中Host列。只有一个IP数字能匹配IP通配
# a# b9 H: R' d0 H/ @, m: l) x符值。
. A% p& B5 P" T0 V- J& A0 \5 d1 D
& G+ V+ _( Q5 \+ x, Q; d4 n3 W1 `" [3 u一个到来的连接可以被在user表中的超过一个条目匹配。例如,一个由
. t9 n1 H/ E8 z2 U# G, @fred从thomas.loc.gov的连接匹配多个条目如上所述。如果超过一个匹配,
( N+ l, W( O, t8 P$ S, D- ~' g服务器怎么选择使用哪个条目呢?服务器在启动时读入user表后通过排序来 2 F* S6 x8 |( z+ H) s
解决这个问题,然后当一个用户试图连接时,以排序的顺序浏览条目,第一
2 h4 ?+ l) _& n4 D) M个匹配的条目被使用。
; u" _4 w2 U4 A1 U5 h. w U/ f" V. {4 Z+ T6 \8 x$ M6 e" y u
user表排序工作如下,假定user表看起来像这样: * ]9 ]; S- x2 r8 S7 R+ l6 d+ `' \7 P
( f. Y+ @& J" F4 X2 R- [5 v" m
6 q$ K5 P5 b2 `+-----------+----------+-
7 A5 p1 n! y- p" b: j) v$ M│ Host │ User │ ... & q$ y) @+ z( M/ ^5 m: r/ F9 t
+-----------+----------+-
$ B( r6 q/ H2 S1 O' `│ % │ root │ ... - e! V8 O3 v! y1 e9 |+ Z I$ R1 n5 K
│ % │ jeffrey │ ... 8 l6 B2 ?$ L, m5 {' [
│ localhost │ root │ ... / \- o; N/ z! o. p8 K
│ localhost │ │ ... ; N! E: H6 `; l* b
+-----------+----------+-
- l5 s- d, |0 l0 ?; C/ s' r" [3 |: E9 Z2 N% |6 f
当服务器在表中读取时,它以最特定的Host值为先的次序排列('%'在 8 Z7 l0 H8 @& J. y4 g5 T) S
Host列里意味着“任何主机”并且是最不特定的)。有相同Host值的条目以
J2 R0 V8 x) @- k4 i# C最特定的User值为先的次序排列(一个空白User值意味着“任何用户”并且
/ e7 ~8 j+ |/ x5 O5 _, y+ ~是最不特定的)。最终排序的user表看起来像这样:
/ L: [5 ?# V8 X6 x% t* G" z2 D1 b3 a; u& F- @6 A+ G6 ~" h" \7 e5 D
. g3 q& D5 E- @ c6 h5 ~1 [+-----------+----------+- 3 x! ?# [& w0 w' e
│ Host │ User │ ... 7 b/ E+ l- P$ q' L! S
+-----------+----------+-
& i+ \0 ]4 V$ Z* n/ O7 v( J│ localhost │ root │ ... & e0 k+ K' B( J$ S% v8 X
│ localhost │ │ ... - }; L+ E0 F. L8 A
│ % │ jeffrey │ ... * L O/ y# {) I( b; \5 O7 V+ w3 X
│ % │ root │ ... 9 V8 U' F* H; m
+-----------+----------+- 1 H/ U+ j0 A6 m- y; n: p5 a
7 ?3 w# n# n5 v0 `# a! |* {( Z u当一个连接被尝试时,服务器浏览排序的条目并使用找到的第一个匹
, k+ `8 y7 k+ l& H% L8 V4 I, S配。对于由jeffrey从localhost的一个连接,在Host列的'localhost'条目 ! |) Z) S4 Y) l6 B6 y( e) i8 R+ Q+ s1 \
首先匹配。那些有空白用户名的条目匹配连接的主机名和用户名。('%'/ % ]3 H0 q( u0 `; ?9 D
'jeffrey'条目也将匹配,但是它不是在表中的第一匹配。) 8 @0 h/ G3 M! V: j5 O. [
+ W! O1 z: a; E这是另外一个例子。假定user桌子看起来像这样: 0 R; a; y0 r, g, a
$ B( s; O2 ~4 x) {& m! [
7 f2 E" Q1 D$ o+----------------+----------+-
3 e! v1 H4 W( j│ Host │ User │ ... , D6 I5 i- r' ]4 b4 u+ b2 u c" @- J
+----------------+----------+- & P+ y/ U- X8 z2 _
│ % │ jeffrey │ ... , c+ w0 J; v2 w5 ?8 E" g" g
│ thomas.loc.gov │ │ ...
7 A1 Z# B: T; y% c+----------------+----------+-
4 ^2 h9 i& o [2 |4 y0 a( b. _3 h! v S" G% N) O7 z8 z
排序后的表看起来像这样:
- H' k& u* x* \, w! X# g7 ~( ~4 P( p6 w$ G+ \! t( F% Y+ r- `6 w
$ ?% T/ p3 |9 T+----------------+----------+- % d4 ]8 ?! m2 T' y1 w) q+ e
│ Host │ User │ ...
$ L7 p' D6 Z. }+----------------+----------+-
' C! I% ~) Q( v, c│ thomas.loc.gov │ │ ...
7 b$ a* K" U# Q# r* L \" R│ % │ jeffrey │ ...
( e* Q. [, c$ v! l3 M5 H/ I: r+----------------+----------+- 3 y( p' P! D+ o9 p N7 d* W3 p; x# j
/ m, S7 s" b. |. Q
一个由jeffrey从thomas.loc.gov的连接被第一个条目匹配,而一个由
+ ]( ^( F) T, \" h, L/ S' x, jjeffrey从whitehouse.gov的连接被第二个匹配。 * o/ k$ t. @, ?2 T Y/ b" T2 x
B0 K" e* a, m# @! R& P5 g& b3 T. t
普遍的误解是认为,对一个给定的用户名,当服务器试图对连接寻找
! C1 K7 [. L( s' ]: R8 _% _4 B5 G匹配时,明确命名那个用户的所有条目将首先被使用。这明显不是事实。
% [' w* s/ r" |' K! A先前的例子说明了这点,在那里一个由jeffrey从thomas.loc.gov的连接没 , Y# w, a* R$ s) ] f B4 H
被包含'jeffrey'作为User字段值的条目匹配,但是由没有用户名的题目匹 % G- G' I" g8 O/ N/ I& s5 A4 b' e
配! 8 F1 n% u; `1 p3 H% [0 x0 T" b
+ l" U2 t9 m+ c w0 W/ g5 r4 o* L
如果你有服务器连接的问题,打印出user表并且手工排序它看看第一个
# |5 a9 h) e/ W" ?& m匹配在哪儿进行。 w% B5 i: X3 ]% t- s5 ]" L
) m+ m$ v# x+ \7 [$ y3 j/ x! N
存取控制,阶段2:请求证实 7 o) T& v) J- V5 p, p; k3 }9 X
一旦你建立了一个连接,服务器进入阶段2。对在此连接上进来的每个 8 w- }- E! Z3 A: z0 a9 `1 }& {9 w- d
请求,服务器检查你是否有足够的权限来执行它,它基于你希望执行的操作
7 Q* w0 P+ u2 d类型。这正是在授权表中的权限字段发挥作用的地方。这些权限可以来子 # j* [+ Z8 d/ B+ r z+ k
user、db、host、tables_priv或columns_priv表的任何一个。授权表用 8 F2 O: J: h8 P% G$ Y0 U
GRANT和REVOKE命令操作。见7.26 GRANT和REVOKE 句法。(你可以发觉参 ; M5 w9 V, j7 W& h0 y' T5 N
考6.6 权限系统怎样工作很有帮助,它列出了在每个权限表中呈现的字段。)
. K# F: ?* h7 R# F0 A7 K# G$ ~
) ]2 t' g' y& O1 [3 R6 S G! |user表在一个全局基础上授予赋予你的权限,该权限不管当前的数据库
8 P }/ S2 U. d是什么均适用。例如,如果user表授予你delete权限, 你可以删除在服务器 * L4 V" \6 R& G1 _/ v0 b" I, P; m* N L
主机上从任何数据库删除行!换句话说,user表权限是超级用户权限。只把 ' I3 k3 @- \) J! c0 D
user表的权限授予超级用户如服务器或数据库主管是明智的。对其他用户, ; D- Z3 t) ^- e/ b7 k* z
你应该把在user表中的权限设成'N'并且仅在一个特定数据库的基础上授权, . h: v G7 n% Q# l4 \
使用db和host表。
' c: N6 V5 v4 ^4 \/ g
1 ]5 w0 R$ f$ I' ^* v2 p" Edb和host表授予数据库特定的权限。在范围字段的值可以如下被指定:
/ b8 G2 W% N8 |- C+ {' ]7 i1 `, [/ M* l1 I* w
通配符字符“%”和“_”可被用于两个表的Host和Db字段。 6 u% N# B* y0 E2 ~9 ~
在db表的'%'Host值意味着“任何主机”,在db表中一个空白Host值意味 0 n$ L3 h \" E+ K7 ?. x- W
着“对进一步的信息咨询host表”。 4 [/ o" _) q" b; a! v
在host表的一个'%'或空白Host值意味着“任何主机”。
! k" u) b2 m% F# f在两个表中的一个'%'或空白Db值意味着“任何数据库”。 5 g( w1 j, M$ U# }( t6 U+ o' q6 h; {2 j
在两个表中的一个空白User值匹配匿名用户。
. |6 @1 v$ {- b. r4 X2 pdb和host表在服务器启动时被读取和排序(同时它读user表)。db表在Host # _' ]+ ?- J. ?! T# F
、Db和User范围字段上排序,并且host表在Host和Db范围字段上排序。对于 4 }' R. I0 T# I8 Y6 ]
user表,排序首先放置最特定的值然后最后最不特定的值,并且当服务器寻找
& j/ d5 ]8 A; x# t! P# T1 l! a匹配入条目时,它使用它找到的第一个匹配。
* d3 R5 _8 w6 | R5 L" P1 l; _3 y% a: \5 @0 z# Y
tables_priv和columns_priv表授予表和列特定的权限。在范围字段的值可 ( Z5 _& r: D: d0 l# g1 o- w5 d
以如下被指定: 0 C( B9 a) N. e! _& z4 c3 ~' J
+ l# _0 |/ ^7 @- `% d9 H通配符“%”和“_”可用在使用在两个表的Host字段。 * f/ k. ~7 a, s
在两个表中的一个'%'或空白Host意味着“任何主机”。 _# M: O0 ?6 b( O& ~2 V6 f$ Q2 t
在两个表中的Db、Table_name和Column_name字段不能包含通配符或空白。 % U- D+ k0 y- A& y7 b/ I
tables_priv和columns_priv表在Host、Db和User字段上被排序。这类似于 : k/ o; G \* S
db表的排序,尽管因为只有Host字段可以包含通配符,但排序更简单。 $ T. W+ K% @/ c5 s3 v6 g
0 a) q# n6 k* L! G3 ]
请求证实进程在下面描述。(如果你熟悉存取检查的源代码,你会注意到这 + A4 B4 Z- T6 u. H2 }- J
里的描述与在代码使用的算法略有不同。描述等价于代码实际做的东西;它只是
3 n+ L. B5 h( F3 z) m不同于使解释更简单。)
1 p/ \/ T, O ]% W: A% F9 y
, `0 @9 M# T, P$ M1 Z7 z$ h3 }对管理请求(shutdown、reload等等),服务器仅检查user表条目,因为那是 / r* z! y, R) Y
唯一指定管理权限的表。如果条目许可请求的操作,存取被授权了,否则拒绝。 " Q/ @& ~' M9 B) |& @0 H
例如,如果你想要执行mysqladmin shutdown,但是你的user表条目没有为你授 " d" h ^/ z* V% `! C( o3 x2 T
予shutdown权限,存取甚至不用检查db或host表就被拒绝。(因为他们不包含
8 ?5 T8 o6 Z. a% gShutdown_priv行列,没有这样做的必要。)
7 J2 E$ ^: M/ C# `/ q# Z( e1 x" c; y4 K' ?
对数据库有关的请求(insert、update等等),服务器首先通过查找user表 ( T4 X1 z0 n# b' z1 X( x: f+ t
条目来检查用户的全局(超级用户)权限。如果条目允许请求的操作,存取被授
8 m" S. G) t2 [. m6 f1 A权。如果在user表中全局权限不够,服务器通过检查db和host表确定特定的用 $ L$ m, K0 j; L% }# s/ E6 U
户数据库权限: ]2 g) j1 q. S1 `
# }; o' B! H/ [: I: G$ I6 t服务器在db表的Host、Db和User字段上查找一个匹配。 Host和User对应连
) G! H$ ]* z6 R- w, ^& k/ s' o接用户的主机名和MySQL用户名。Db字段对应用户想要存取的数据库。如果没有 , _7 U' {- B0 |' V. l
Host和User的条目,存取被拒绝。
0 I3 E" A0 y6 u+ W/ d' P( Z+ a如果db表中的条目有一个匹配而且它的Host字段不是空白的,该条目定义用 : w' Z* {& @; }
户的数据库特定的权限。
6 Q; I; ]! Y( I. g6 U如果匹配的db表的条目的Host字段是空白的,它表示host表列举主机应该被 ' {6 \, j8 V3 Q7 b* N; j
允许存取数据库的主机。在这种情况下,在host表中作进一步查找以发现Host和 8 ]- B& G; k5 c2 y& @- E$ C
Db字段上的匹配。如果没有host表条目匹配,存取被拒绝。如果有匹配,用户数 2 m9 P- H5 o5 G* ~8 u) O) P
据库特定的权限以在db和host表的条目的权限,即在两个条目都是'Y'的权限的交
2 h9 W( L5 L D集(而不是并集!)计算。(这样你可以授予在db表条目中的一般权限,然后用host ' v* p e. n' }4 \. r, B
表条目按一个主机一个主机为基础地有选择地限制它们。) ( @9 C+ W1 M! u \' A8 d3 {7 G5 D) M* r
在确定了由db和host表条目授予的数据库特定的权限后,服务器把他们加到 : l; c5 P" t4 b% ]
由user表授予的全局权限中。如果结果允许请求的操作,存取被授权。否则,服
( `( H7 { y6 z0 H务器检查在tables_priv和columns_priv表中的用户的表和列权限并把它们加到
5 T& f5 o# k, E$ g$ `9 K( H' x用户权限中。基于此结果允许或拒绝存取。
( Q& L& ?3 ]/ a$ x2 Y$ Y- ?
+ m& n t" b1 @$ u9 j( Z用布尔术语表示,前面关于一个用户权限如何计算的描述可以这样总结:
2 i7 N0 ~: p6 J/ o( d1 w! g" O8 h0 _+ @! k9 c5 Q9 F; N
global privileges : i- r1 L( |( S8 C
OR (database privileges AND host privileges)
! s$ h, \6 r6 R4 k: mOR table privileges
) j N8 {7 T2 R I2 Q% Q6 _OR column privileges
' G1 h* u! ~- n4 o6 T$ ]
$ _9 D. k3 H7 t. [4 I. U它可能不明显,为什么呢,如果全局user条目的权限最初发现对请求的操作不 $ o# E1 f6 j( G
够,服务器以后把这些权限加到数据库、表和列的特定权限。原因是一个请求可能 ! u+ j+ C6 l. I/ K+ J* `1 c
要求超过一种类型的权限。例如,如果你执行一个INSERT ... SELECT语句,你就都
+ I# M/ a5 k0 Y( w3 Q) y3 M要insert和select权限。你的权限必须如此以便user表条目授予一个权限而db表条
1 Z; c2 Y; d* y" y( `& D目授予另一个。在这种情况下,你有必要的权限执行请求,但是服务器不能自己把
: _3 w! a6 r) u" K8 r. @两个表区别开来;两个条目授予的权限必须组合起来。
' a, L: \( T5 M0 s {! [4 X: X+ x- g9 R1 w# | g8 [
host表能被用来维护一个“安全”服务器列表。在TcX,host表包含一个在本
; d# d& p' m, q1 p- S地的网络上所有的机器的表,这些被授予所有的权限。 1 |! m m0 k* y$ |4 ]% z
) R/ M6 ~; x, } ?8 f- a( l) r+ X
你也可以使用host表指定不安全的主机。假定你有一台机器public.your. # C/ O+ z$ y/ c
domain,它位于你不认为是安全的一个公共区域,你可以用下列的host表条目子允 7 d& ]. ]( u" F& I1 h
许除了那台机器外的网络上所有主机的存取: " G; l Q$ e3 i9 I
7 [0 m1 W$ [% l3 w5 i' q
: c* Z: U: y, J, r: ^. ^9 B8 I
+--------------------+----+- & L. V! Q$ R7 D M( Z% D
│ Host │ Db │ ...
5 D, R4 s0 i6 J4 I" Z+--------------------+----+-
7 D4 T" r7 A" ?6 l0 j0 N5 |9 {7 S│ public.your.domain │ % │ ... (所有权限设为 'N') q& v1 ]! T8 o
│ %.your.domain │ % │ ... (所有权限设为 'Y') 0 u" {( A9 D# z
+--------------------+----+-
% D# L: a( {3 L# q, n( f* B( X' H
当然,你应该总是测试你在授权表中的条目(例如,使用mysqlaccess)让你确保
8 Y# U$ O4 _+ g( e) m6 Y! ~) W. C9 ]你的存取权限实际上以你认为的方式被设置。 , v( _, _4 T! D4 Y
. R& s3 k/ ` R
权限更改何时生效
5 U4 C8 @; O8 \8 [! t- m当mysqld启动时,所有的授权表内容被读进存储器并且从那点生效。 0 T9 E5 j' `# g8 G7 {1 ]2 w
, {. Y& J' z2 K& r% n3 L) y. q
用GRANT、REVOKE或SET PASSWORD对授权表施行的修改会立即被服务器注意到。
; ~* U* u. P R& U5 d8 S Y+ R
如果你手工地修改授权表(使用INSERT、UPDATE等等),你应该执行一个FLUSH ) ^* S6 p- J& ]" a5 S" j
PRIVILEGES语句或运行mysqladmin flush-privileges告诉服务器再装载授权表,否
, F/ J4 Y' B8 w# ^# c! R6 l% G0 l则你的改变将不生效,除非你重启服务器。 . R- \& Q. f. g* F( g
4 j2 b9 s" u/ U, Y! G5 N
当服务器注意到授权表被改变了时,现存的客户连接有如下影响:
- m6 R# B: q; D6 S5 U9 S- D: `/ |' h1 W6 g
表和列权限在客户的下一次请求时生效。 . T! D' @& Q5 A* \' i+ Q
数据库权限改变在下一个USE db_name命令生效。
$ e: X% Q! r# F! X4 ~- z( F全局权限的改变和口令改变在下一次客户连接时生效。 % a. ]! X8 A# {* a c4 g9 o
' E. o6 f8 t1 A; C. _9 G1 j建立初始的MySQL权限 ( {8 q' O; w6 x, R; Z
在安装MySQL后,你通过运行scripts/mysql_install_db安装初始的存取权限。 % M" ]5 d0 o5 Y$ D/ @
scripts/mysql_install_db脚本启动mysqld服务器,然后初始化授权表,包含下列
5 n* k3 h) N1 {权限集合: ' L. q4 ~; O/ I& H
3 c, g3 W. ~' L3 _; @MySQL root用户作为可做任何事情的一个超级用户被创造。连接必须由本地主
7 r! R# o3 N$ I/ W: S# J机发出。注意:出世的root口令是空的,因此任何人能以root而没有一个口令进行 9 H8 K/ ]6 L+ |' {: H/ |
连接并且被授予所有权限。 : [) G" r' M6 V* f, m6 J$ P
一个匿名用户被创造,他可对有一个'test'或以'test_'开始的名字的数据库 9 {0 P; k; R7 V, w4 O: P
做任何时期事情,连接必须由本地主机发出。这意味着任何本地用户能连接并且视
3 @! B/ x$ \$ @3 S; J为匿名用户。
! C' m0 m7 Y. R- B其他权限被拒绝。例如,一般用户不能使用mysqladmin shutdown或
Y$ Z' E3 s9 r: r Vmysqladmin processlist。 . q3 f7 i; Z9 ]. O: X
注意:对Win32的初始权限是不同的。 , W/ p- U! o8 L
+ k4 V4 n( o2 F- b0 c
既然你的安装初始时广开大门,你首先应该做的事情之一是为MySQL root用户
2 P u" |5 W0 \" [, O- X0 b! e指定一个口令。你可以做如下(注意,你使用PASSWORD()函数指定口令):
% i3 R; ?$ T; a/ ?, U( B- |' Q1 Q f+ |! P
shell> mysql -u root mysql # X. s" N% C/ N4 g
mysql> UPDATE user SET Password=PASSWORD('new_password')
2 }& H$ D' w% o+ VWHERE user='root'; $ | B" g# I4 n& B
mysql> FLUSH PRIVILEGES;
% y! j: e4 b6 h; u
& S# X% N/ Z: q, o8 ]5 D1 u在MySQL 3.22和以上版本中,你可以使用SET PASSWORD语句:
/ Y& j @2 [4 k8 X! H/ q0 \) z! m1 [% y/ n& y
shell> mysql -u root mysql % O( ^; E% X+ [2 r( n/ w
mysql> SET PASSWORD FOR root=PASSWORD('new_password'); ! }- l) `# f$ `' [
$ @. S: }% B ?: j: C1 l& a设置口令的另一种方法是使用mysqladmin命令:
$ H( S4 X4 L7 ~# j5 z- Y: c/ ]: l9 R+ B* E
shell> mysqladmin -u root password new_password & h4 u; I: c' d8 G7 e3 m3 K
% ^. E* P- X7 Q7 W
注意:如果你使用第一种方法在user表里直接更新口令,你必须告诉服务器 2 W& Z: |7 U# U" C/ V& S
再次读入授权表(用FLUSH PRIVILEGES),因为否则改变将不被注意到。
$ e) x* W& ~% F" w. f8 H$ |1 n. g6 P$ ^% s2 @
一旦root口令被设置,此后当你作为root与服务器连接时,你必须供应那个 ) e0 N3 I9 d6 [. Y$ O2 A. q9 c7 c5 N
口令。
& W2 M! u3 {4 |; s4 n6 r9 C
0 F, D6 E |6 H3 C1 T+ L你可能希望让root口令为空白以便当你施行附加的安装时,你不需要指定它
" p9 a- Y) e) v b: X9 m或测试,但是保证在任何真实的生产工作中使用你的安装之前,设置它。 / t r. U3 P5 W
5 n1 d* n$ b4 O1 s看看scripts/mysql_install_db脚本,看它如何安装缺省的权限。你可用它 , t7 n! h) \4 N& d- p
作为一个研究如何增加其他用户的基础。
- a& n$ C8 {4 a5 Z1 m& q8 N/ n
6 y: B/ s: S& ?如果你想要初始的权限不同于上面描述的那些,在你运行mysql_install_db
5 U7 d/ Z! m( x/ g/ ]之前,你可以修改它。
0 L) \5 N! K0 d4 c6 V- L: D, B$ ~' a) K+ \. e4 Q. i2 S" x3 u
为了完全重建权限表,删除在包含mysql数据库的目录下所有“*.frm”,
5 \3 a# l7 a- Y% \$ J* K“*.MYI”和“*.MYD”文件。(这是在数据库目录下面命名为“mysql”的目录,
4 v$ V; z& s a' L1 l. R当你运行mysqld --help时,它被列出。)然后运行mysql_install_db脚本,可能 ! P/ l: s6 C+ A3 `7 U s2 p
在首先编辑它拥有你想要的权限之后。 0 c' ^, d: N5 t
3 I0 P6 m8 n& s1 j ~, X) i
注意:对于比MySQL 3.22.10旧的版本,你不应该删除“*.frm”文件。如果
2 W7 U" D# g% P3 |, {你偶然做了,你应该在运行mysql_install_db之前你的MySQL分发中拷回它们。 ! v' P7 c7 ?. Q% D8 h
, L$ D: _3 B3 o/ z$ G
向MySQL增加新用户权限
" _' b. z8 [! Y' c你可以有2个不同的方法增加用户:通过使用GRANT语句或通过直接操作MySQL授
$ b/ |5 ]- K ?: l0 U权表。比较好的方法是使用GRANT语句,因为他们是更简明并且好像错误少些。
4 B( `' u' ]% }5 j( j- W
. [! I. d1 n$ {$ \# N! P t下面的例子显示出如何使用mysql客户安装新用户。这些例子假定权限根据以前 - m6 B3 v! Z4 o2 {0 p8 L6 @5 i
的章节描述的缺省被安装。这意味着为了改变,你必须在mysqld正在运行同一台 X& i* O- W# D- O0 k
机器上,你必须作为MySQL root用户连接,并且root用户必须对mysql数据库有
2 r1 p' w" [3 W7 ainsert权限和reload管理权限。另外,如果你改变了root用户口令,你必须如下 6 _' i u1 b/ J4 X+ R% R- E" x
的mysql命令指定它。 , U& I5 w7 }. c' R' G/ Y
0 k! z* m* c- Y7 g; U' P% o' J
你可以通过发出GRANT语句增加新用户:
) m& ~" H& d. W: B: p k* N5 v- U* ~* b" B5 o: M
shell> mysql --user=root mysql
; F H; P( `" D! `1 Cmysql> GRANT ALL PRIVILEGES ON *.* TO monty@localhost
8 V) t$ l4 Z# M. o% n2 MIDENTIFIED BY 'something' WITH GRANT OPTION;
K' f8 N; _$ O+ X# Umysql> GRANT ALL PRIVILEGES ON *.* TO monty@"%" ( t& q! Q' D2 O% G, C
IDENTIFIED BY 'something' WITH GRANT OPTION;
( ]1 f) E" v+ e. Dmysql> GRANT RELOAD,PROCESS ON *.* TO admin@localhost;
: t. n* N0 b4 G* ^0 {9 D8 cmysql> GRANT USAGE ON *.* TO dummy@localhost;
9 @$ K; M1 U$ n
! ]( I8 S; f0 v. a+ [/ }# j这些GRANT语句安装3个新用户: 4 }( t# F6 V4 `1 ^
7 G, r6 k& G8 |2 K8 q4 pmonty 7 \( |' w8 m3 u* T# D$ b. ^
可以从任何地方连接服务器的一个完全的超级用户,但是必须使用一个 : L! N/ V6 V. z. I& C; m
口令('something'做这个。注意,我们必须对monty@localhost和monty@"%" : g* t+ G0 f' K1 H+ a
发出GRANT语句。如果我们增加localhost条目,对localhost的匿名用户条目 & c/ }3 [* J+ j0 G! C
在我们从本地主机连接接时由mysql_install_db创建的条目将优先考虑,因为 & a( C p) y# V8 U. R
它有更特定的Host字段值,所以以user表排列顺序看更早到来。
; l' V8 ?/ T; T$ v+ _' Oadmin
# H4 b+ w6 e9 }1 `2 B. I" u, `6 d7 t可以从localhost没有一个口令进行连接并且被授予reload和process管理
1 T" c' a' t! U" o- V权限的用户。这允许用户执行mysqladmin reload、mysqladmin refresh和 " t! E4 G; I# n2 ~- `# c
mysqladmin flush-*命令,还有mysqladmin processlist。没有授予数据库有
$ Z3 z% ~: P. d$ G' X关的权限。他们能在以后通过发出另一个GRANT语句授权。 1 G# W# A4 n% ]1 X% a* V
dummy . f; k1 x* t+ f
可以不用一个口令连接的一个用户,但是只能从本地主机。全局权限被设
% A" ^, D, x8 X# J5 \/ x置为'N'--USAGE权限类型允许你无需权限就可设置一个用户。它假定你将在以 + V [9 l% _5 b1 P
后授予数据库相关的权限。 3 C1 i$ J) d8 D w! d) L) a
你也可以直接通过发出INSERT语句增加同样的用户存取信息,然后告诉服
! ]3 J2 K" T+ a: z; m2 T8 x! Y' p务器再次装入授权表: 0 X9 R$ {$ ^6 ~1 ]- q+ o
5 q4 W% F( q; w: f$ cshell> mysql --user=root mysql 3 E: u+ w7 j) I0 ]3 ?
mysql> INSERT INTO user VALUES('localhost','monty',PASSWORD , k7 I/ s. H( S8 ]
('something'), 4 ~& H" i2 N2 d1 N+ K
'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y', + E, @# K! N& z6 V# s' \
'Y','Y')
) `* c1 |1 E0 N! z2 Gmysql> INSERT INTO user VALUES('%','monty',PASSWORD('something'),
1 |" E" h5 I( M. @$ W+ S'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y',
! b# F% j: E. u- @: m4 Y'Y')
( C. B6 l4 m d2 Hmysql> INSERT INTO user SET Host='localhost',User='admin', & C2 ^# n$ f @9 a( [* ^5 @1 f
Reload_priv='Y', Process_priv='Y';
% y9 S+ d* F0 j6 Z3 l! Q! ]4 R/ {* Tmysql> INSERT INTO user (Host,User,Password)
) W$ t) c+ w% }. n0 UVALUES('localhost','dummy','');
p I4 P4 ]4 `4 g' o6 c5 R; p' Omysql> FLUSH PRIVILEGES;
1 f# b. L) O/ l% }' c5 S/ p7 M% ?& b" o! a# R2 ~
取决于你的MySQL版本,对上述,你可能必须使用一个不同数目'Y'值(在
+ p, G( _6 f# T3.22.11以前的版本有更少的权限列)。对admin用户,只用在3.22.11开始的版 % A3 i7 Q, x1 J; r7 C( W1 E
本具有的更加可读的INSERT扩充的语法。 * t: |6 H7 s. K
/ I) g) S. y" g! y
注意,为了设置一个超级用户,你只需创造一个user表条目,其权限字段设为
5 W& t6 \( t: \; b: q'Y'。不需要db或host表的条目。 ) N& V1 n; K6 i( n ~
; A( z% a% h& m" H9 n
在user表中的权限列不是由最后一个INSERT语句明确设置的(对dummy用户),
/ l4 D' @9 R0 v& F因此那些列被赋予缺省值'N'。这是GRANT USAGE做的同样的事情。 ' w- S- f( D/ E& x. w
$ Z! v3 @. i" G' x# _下列例子增加一个用户custom,他能从主机localhost、server.domain和
4 g0 W/ C, X% d: _whitehouse.gov连接。他只想要从localhost存取bankaccount数据库,从
s0 W a4 T* f: v8 I7 [whitehouse.gov存取expenses数据库和从所有3台主机存取customer数据库。他 0 m `6 o$ ~- U J1 Y4 ]3 z
想要从所有3台主机上使用口令stupid。 ' y: G( b# N0 z6 w f% i
i6 N3 ^& S/ w% f3 \* s5 Q1 ?为了使用GRANT语句设置个用户的权限,运行这些命令:
$ I, q7 R8 B( X, z4 P h. \" ^. ~
2 N, ]. B& |- ^7 C& c3 {shell> mysql --user=root mysql 6 P. w7 k$ G8 x! X# p, `
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
5 I. U7 ]& p$ a1 e: vON bankaccount.*
3 @3 P5 K0 z8 @ lTO custom@localhost % Q. c9 h; |* |/ u. H
IDENTIFIED BY 'stupid'; , Z+ n2 G9 J) _& c
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP & Q9 ~# Z4 `/ n0 Z
ON expenses.* X+ R, d! s: f& o
TO custom@whitehouse.gov , E# }5 ]- ]2 L- C' h
IDENTIFIED BY 'stupid'; 9 ?3 O" }. f7 M O3 i
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP 6 r' ?6 n" q% z0 @7 S; y& ]
ON customer.*
- A2 }- [/ y7 H/ ]0 HTO custom@'%' : ?+ I& T) N0 P1 F; L
IDENTIFIED BY 'stupid'; % O& S) i( A+ e" j" F4 ~
$ o: \: r8 m$ I6 J) ?; f) e通过直接修改授权表设置用户权限,运行这些命令(注意,在结束时
0 U" h, j. g+ j5 EFLUSH PRIVILEGES): ) B1 J2 V( p5 ], k# y
& s" y `3 |% `
shell> mysql --user=root mysql ) _" B* ]/ w5 s2 L
mysql> INSERT INTO user (Host,User,Password) + T' X& F6 p Q t; j5 G- B) {
VALUES('localhost','custom',PASSWORD('stupid'));
r; R: G$ F- t( wmysql> INSERT INTO user (Host,User,Password) 4 ]& g- u5 r/ L
VALUES('server.domain','custom',PASSWORD('stupid')); % T# k/ P2 K8 L$ Q3 }
mysql> INSERT INTO user (Host,User,Password)
$ ~8 B/ f( i8 ~0 f0 xVALUES('whitehouse.gov','custom',PASSWORD('stupid'));
0 X' F% D$ q5 D/ Rmysql> INSERT INTO db
- E# h1 }. a8 j7 @2 \# U: |(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
3 W! r7 Q9 Z0 K; w1 G) Y) OCreate_priv,Drop_priv) `! P6 Y! q7 F2 @
VALUES
4 S8 b+ `9 u. D. F" p0 O('localhost','bankaccount','custom','Y','Y','Y','Y','Y','Y');
y" v) V- w, O: p$ H- ?6 V, c$ ]mysql> INSERT INTO db 4 t/ o+ _4 q5 @9 `, L6 d
(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
, X; t3 R1 j# j( yCreate_priv,Drop_priv) . l2 |8 A3 @' b+ Z( h
VALUES 2 E, Q2 p' }" T& `
('whitehouse.gov','expenses','custom','Y','Y','Y','Y','Y','Y'); , S: m& d$ F5 P& _5 M$ j8 A- z
mysql> INSERT INTO db 1 J2 ?; E$ Y/ l) b% p* _
(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv, 7 U8 R: Z+ h% q$ t" {
Create_priv,Drop_priv) 6 v8 n6 \1 |) f5 K% A5 l. z
VALUES('%','customer','custom','Y','Y','Y','Y','Y','Y');
) P# Y# N) b* y' \mysql> FLUSH PRIVILEGES; % p8 ]5 O7 J, K4 X8 d* q) w
7 v1 C7 y9 e4 ~; m3 R
头3个INSERT语句增加user表条目,允许用户custom用给定口令从不同的主机 / E1 B8 L- O& ^% l
进行连接,但是没有授予任何许可(所有权限被设置为缺省值'N')。后3个INSERT ) B& h M J: \6 ~; G- ^
语句增加db表条目,授予custom以bankaccount、expenses和customer数据库权限,
5 i H1 o" C7 \. U! g但是只能在从正确的主机存取时。通常,在授权表直接被修改时,服务器必须被告 7 @7 x8 `; X. ]- l
知再次装入他们(用FLUSH PRIVILEGES)以便使权限修改生效。 ! K* m! k5 h6 d% Z# Y) |
( w' j7 Q5 k- H w4 f4 _
如果你想要给特定的用户从一个给定的域上的任何机器上存取权限,你可以发 8 s* J, U7 g0 h7 |. Z
出一个如下的GRANT语句:
- L5 k* O- U P C9 @3 _7 g' o0 Q: l0 \* J
mysql> GRANT ...
+ z) E1 s0 P6 j2 u( HON *.*
' R3 j( X, k8 f. @TO myusername@"%.mydomainname.com" 0 Y0 r7 Z b4 I! c) @
IDENTIFIED BY 'mypassword';
w6 ]% }7 F2 K, n- |+ q0 t$ A% A) u+ [
为了通过直接修改授权表做同样的事情,这样做: $ u) U* B- v# {5 ^; P& X. d
" Y2 v5 E6 V/ u1 _0 h$ gmysql> INSERT INTO user VALUES ('%.mydomainname.com', 'myusername',
7 \, O2 X& W" P& H4 T1 K9 l5 aPASSWORD('mypassword'),...); - w. X% [7 [* C; _* W, ^
mysql> FLUSH PRIVILEGES; 5 g6 l4 \6 J! q0 y0 s
# s3 y: ]; T4 \; Z1 U! u你也可以使用xmysqladmin、mysql_webadmin甚至xmysql在授权表中插入、改变
+ K9 }5 E* H. u9 B) d) o; I# B4 B( f和更新值。你可以在MySQL的Contrib目录找到这些实用程序。
! M( ~" H* a0 _- f v2 t x
. o, c' {- `+ g& N6 j) \2 |3 c6 O怎样设置口令 - e6 g: q( [2 V. Z( j8 D; `2 O
在前面小节的例子里说明了一个重要的原则:当你使用INSERT或UPDATE语句存
) l1 r* {4 z" V: }. B1 r w2 O3 \储一个非空的口令时,你必须使用PASSWORD()函数加密它。这是因为在user表中以 - ?# S1 K( b4 `% E8 H. S
加密形式存储口令,而不是作为纯文本。如果你忘记这个事实,你可能像这样试图 * U; M4 B( k5 j% A9 z
设置口令: + K, `, K. A6 x* C2 p3 `/ t' B- U t
5 R. I+ r7 F! C% A. n
shell> mysql -u root mysql
4 f6 S( S t Y/ u6 Q( n8 Lmysql> INSERT INTO user (Host,User,Password) VALUES('%','jeffrey',
8 V- Y2 n& Y' e6 {6 p'biscuit');
H) T8 f- p9 A4 Z+ b: R3 l0 E" Amysql> FLUSH PRIVILEGES
+ }1 H }( U* D3 Q6 W8 p' z5 w* b, i' y$ R l/ b( f
结果是纯文本值'biscuit'作为口令被存储在user表中。在用户jeffrey试图用 ' m0 o9 a( W) e( e' x7 f, c4 V. p
这个口令连接服务器时,mysql客户用PASSWORD()加密它并且将结果送给服务器,服 9 J5 E# O5 M( O! O0 U9 R
务器比较在user表中的值(它是纯文本值'biscuit')和加密的口令(而不是 ; y; c% W! D: c- J2 y
'biscuit'),比较失败并且服务器拒绝连接: % {9 u( [- M N
# k; ?, `3 G1 A: O1 Mshell> mysql -u jeffrey -pbiscuit test + |4 K4 L% \/ G
Access denied
" M/ I! I1 M3 I/ W' A
- ~+ m4 b& |) g# g, b7 m- Z因为当他们被插入user表时,口令必须被加密,相反,INSERT语句应该象这样
" s) P3 n8 h9 o- X被指定:
}0 V7 K' p: P# J
5 c$ R5 F. I1 nmysql> INSERT INTO user (Host,User,Password) / Z! L |/ U/ V$ P5 x2 l- u
VALUES('%','jeffrey',PASSWORD('biscuit')); , }" I3 K8 i7 z
2 n) M+ j1 C5 q; J当你使用SET PASSWORD语句时,你也必须使用PASSWORD()函数: " U- n. A$ u+ t4 i. H4 F+ \4 W
( P2 n# L5 f9 S* R, G! U
mysql> SET PASSWORD FOR jeffrey@"%" = PASSWORD('biscuit');
5 E& K5 P6 N+ S9 y4 y. b' i; e/ i* I. ?& ]
如果你使用GRANT ... IDENTIFIED BY语句或mysqladmin password命令设置口
8 c; u+ V/ e* T/ ^! N, }" z: O令,PASSWORD()函数是不必要的。他们都考虑到为你加密口令,多以你可像这样指
' q( z) T, V; A' H2 r+ _定一个口令'biscuit':
, X- u! e$ K+ t# j0 ?) x1 b; h. t
mysql> GRANT USAGE ON *.* TO jeffrey@"%" IDENTIFIED BY 'biscuit';
* @6 e1 o* N# N- U9 H" s
; j0 r6 ^, R; Q2 n或
0 A" D8 o4 V$ ~
: y" f7 e/ _2 {, tshell> mysqladmin -u jeffrey password biscuit o7 ^, x+ _) q2 H
注意: PASSWORD()不是以在Unix口令加密的同样方法施行口令加密。你不应 # N! `, T4 |: J3 x
该假定如果你的Unix口令和你的MySQL口令是一样的,PASSWORD()将导致与在Unix 7 W# ]- b9 t, b$ u9 @
口令文件被存储的同样的加密值。见6.2 MySQL 用户名和口令。 t' ~) Y; ^- Q4 A
0 ~1 U* e. T1 x3 O9 wAccess denied错误的原因 & d) D; E) p# b: P" E8 t
当你试着联接MySQL服务器时,如果你碰到Access denied错误,显示在下面
& N& T: I+ Y1 p/ f ?" H的表指出一些你能用来更正这个问题的动作:
# k2 d+ R+ f5 Y+ i5 m& Z7 z1 h* n2 @3 ?
你是在安装MySQL以后运行mysql_install_db的脚本,来设置初始授权表内容
% D) d* B" G/ X) k/ ]# q吗?如果不是,这样做。见6.10 设置初始MySQL权限。通过执行这个命令测试初
% }8 a$ J Q% |+ }' }始权限: 4 [ M; i' k1 U4 c9 y; O% M
shell> mysql -u root test & [$ {1 ]) o( w X! l/ W
. D( z& S" x: @: ^9 N+ {' k
服务器应该让你无误地连接。你也应该保证你在MySQL数据库目录有一个文件
k, P5 R; C5 w) b+ N! ~3 c, H% W“user.MYD”。通常,它是“PATH/var/mysql/user.MYD”,在此PATH是MySQL安 ! q6 r: h7 I9 b2 E5 y" d
装根目录的路径。
. I4 R7 {( P H* t3 R! W
4 z1 f: r6 ]/ y8 }$ I: q在一个新的安装以后,你应该连接服务器并且设置你的用户及其存取许可:
% J# t, D! c7 I9 ashell> mysql -u root mysql
; O+ |" ]3 n! a- N% R5 w `5 F: S+ E7 }( b) q3 P1 i9 M9 f
服务器应该让你连接,因为MySQL root用户初始时没有口令。既然那也是一个
2 R# c e4 \4 l0 t( E( o安全风险,当你正在设置其他MySQL用户时,设定root口令是一件重要的事请。如
v: L" H! U' f1 }3 _+ f果你作为root尝试连接并且得到这个错误: ' c; m5 i1 H! C$ R- N2 K
" p5 R; P1 Y; O+ u1 j+ ]& n9 l
Access denied for user: '@unknown' to database mysql * t; s ^, \. N
9 a+ `2 `. o) j# d. O' V) t8 k这意味着,你没有一个条目在user表中的一个User列值为'root'并且mysqld
9 M8 w- N. F& n: \; X不能为你的客库解析主机名。在这种情况下,你必须用--skip-grant-tables选项 4 B( ?5 X. R! c+ J& a
重启服务器并且编辑你的“/etc/hosts”或“\windows\hosts”文件为你的主机 $ m2 w. H4 ?. R3 ^0 y+ p
增加一个条目。
: \* g% ?& r' w" n' o9 S& G6 z3 }/ e# a) e. w0 y* f5 G7 k _4 y
如果你从一个3.22.11以前的版本更新一个现存的MySQL安装到3.22.11版或以 : p4 P, A/ V$ z: T! O
后版本,你运行了mysql_fix_privilege_tables脚本吗?如果没有,运行它。在 ' X# ^- g" I! v. D3 u8 H: r! h
GRANT语句变得能工作时,授权表的结构用MySQL 3.22.11修改 。 * J( u9 |' o4 x* |. p9 u( n
如果你直接对授权表做修改(使用INSERT或UPDATE语句)并且你的改变似乎被 & s8 B4 `+ W# c; S4 r
忽略,记住,你必须发出一个FLUSH PRIVILEGES语句或执行一个mysqladmin
3 |- w- g( N6 {+ P Lflush-privileges命令导致服务器再次读入表,否则你的改变要道下一次服务器被
6 W/ v8 i# z( @重启时再生效。记住在你设定root口令以后,你将不需要指定它,直到在你清洗
4 F5 f1 @' N7 k. \(flush)权限以后,因为服务器仍然不会知道你改变了口令!
6 W1 S8 H2 P0 W如果你的权限似乎在一个会话(session)当中改变了,可能是一个超级用户改变
5 ]6 ]# ~# b( @ p) V6 A* D了他们。再次装入授权表作用于新客户连接,但是它也影响现存的连接,如6.9 权
. m; _+ X. l& p! B# Z7 @限改变何时生效小节所述。 ) u8 n' m/ t' _. D2 j
为了测试,用--skip-grant-tables选项启动mysqld守护进程,然后你可以改变 ( e y2 }' C/ ^" g& K# h
MySQL授权表并且使用mysqlaccess脚本检查你的修改是否有如期的效果。当你对你的 ; K! x/ d6 F) n- a1 e
改变满意时,执行mysqladmin flush-privileges告诉mysqld服务器开始使用新的权 ' O1 p0 I1 O& r% c- F
限表。注意:再次装入授权表覆盖了--skip-grant-tables选项。这允许你告诉服务
- d$ ?1 n( O# {1 b器开始使用授权表,而不用停掉并重启它。
2 J, h. g( a! v) t9 i6 K. r8 f如果你有一个Perl、Python或ODBC程序的存取问题,试着用mysql -u user_name
3 T v8 K2 X* i3 F/ Wdb_name或mysql -u user_name -pyour_pass db_name与服务器连接。如果你能用
* C. F* W6 a! ?mysql客户连接,这是你程序的一个问题而不是存取权限的问题。(注意在-p和口令
! [# P' q$ C) @之间没有空格;你也能使用--password=your_pass句法指定口令。) 9 I; t1 T. H% ]+ L; ` C
如果你不能让口令工作,记得如果你用INSERT, UPDATE或SET PASSWORD语句
" q8 B: r% B) O设置口令,你必须使用PASSWORD()函数。如果你用GRANT ... INDENTIFIED BY语 5 p2 Y$ E& t' z. ]
句或mysqladmin password命令指定口令,PASSWORD()函数是不需要的。
, G( W3 z& l9 M: [' elocalhost是你本地主机名的一个同义词,并且也是如果你不明确地指定主机
% y, J4 Y% n! U( P$ Z' V而客户尝试连接的缺省主机。然而,如果你正在运行于一个使用MIT-pthreads的系
# b. h6 U& V( g统上,连接localhost是不行的(localhost连接使用Unix套接字进行,它没被 MIT
2 E4 Y( d# A2 x- ]$ }* g8 H1 u7 U-pthreads支持),为了在这样的系统上避免这个问题,你应该使用--host选项明确
0 t7 L4 H3 Q' ?- p地命名服务器主机,这将做一个 TCP/IP连接到mysqld服务器。在这种情况下,你
/ o) Y' C1 i5 B# R' r, \: z" e必须有在服务器主机上的user表中条目的你真实的主机名。(即使你在服务器同一
: m1 _, g& b: l% @1 @8 i8 G台的主机上运行一个客户程序,这也是真的。)
1 w( e- x8 o! T1 q+ e当尝试用mysql -u user_name db_name与数据库连接时,如果你得到一个 6 B' `1 |; z' `( r0 B
Access denied错误,你可能有与user桌有关的问题,通过执行mysql -u root + m' k" w! M8 X! V# A$ u/ K
mysql并且发出下面的SQL语句检查:
9 I- |+ j* V+ X. k' @8 }mysql> SELECT * FROM user;
( F- l+ a- s0 @( y$ Y7 [
; v( B z h1 y$ m- U5 Y结果应该包含一个有Host和User列的条目匹配你的计算机主机名和你的MySQL用户 # f& N' L6 Y0 u9 B
名。 ! Z( g+ t+ n+ n+ @9 S% s
1 y8 G u( n O! }
Access denied错误消息将告诉你,你正在用哪个用户尝试登录,你正在试图 7 s* q4 }. g- b" s8 G! A- V' k& p
用连接哪个主机,并且你是否正在使用一个口令。通常,你应该在user表中有一
; n" ], B* S/ G/ p: Z3 }8 I9 V1 x个条目,正确地匹配在错误消息给出的主机名和用户名。 ! t; D9 J, U. C
如果当你试着从一个不是MySQL服务器正在运行的主机上连接时,你得到下列 A W7 v' Y4 \. [4 `3 Q- a1 B
错误,那么在user表中没有匹配那台主机行: 9 _+ B" N( r% u5 [/ l8 S& U
Host ... is not allowed to connect to this MySQL server
P1 F. H* F0 z6 K* h$ c5 b
( Z# X% l# Q4 n1 C你可以通过使用mysql命令行工具(在服务器主机上!)修正它,把你正在试 / u5 W9 p& I" b4 o% U# N. s
图连接的用户/主机名组合新加一行到user表中。如果你不在运行MySQL 3.22并且 - r- C: _- \+ m; V% ^) B/ ^
你不知道你正在从它连接的机器的IP数字或主机名,你应该把一个'%'条目作为 \: Y1 a9 p) U0 {- h( E8 @
Host列值放在user表中并且在服务器机器上使用--log选项重启mysqld。在试图从
8 H0 o$ {3 G' F客户机器连接以后,在MySQL记录文件中的信息将显示你如何真正进行连接。( ( ^; w3 O4 k) C6 Q
然后用在记录文件上面显示出的实际的主机名代替user表中的'%'条目。否则, ) A/ s$ `. N- T% z! H/ L/ U
你将有一个不安全的系统。)
, r* |8 w0 v7 P8 o
) _$ i& o+ j! [: e5 w如果mysql -u root test工作但是mysql -h your_hostname -u root test
& Y' ^% P. j5 m# j: l导致Access denied,那么在user表中你可能没有你的主机的正确名字。这里的 ; u. `% W! q9 F* m8 M3 w- s+ F
一个普遍的问题是在user表条目中的Host值指定一个唯一的主机名,但是你系统
) C0 H" I1 v# M1 {的名字解析例程返回一个完全正规的域名(或相反)。例如,如果你在user表中有
5 A* b: V- | j6 n2 V一个主机是'tcx'的条目,但是你的 DNS告诉MySQL你的主机名是'tcx.subnet.
4 s: n: z; U' }, v6 ise',条目将不工作。尝试把一个条目加到user表中,它包含你主机的IP数字作
# N& W! U# C) G9 {- \$ `为Host列的值。(另外,你可以把一个条目加到user表中,它有包含一个通配符
0 S5 a9 L+ q! d1 ~4 h6 d如'tcx.%'的Host值。然而,使用以“%”结尾的主机名是不安全的并且不推荐!)
# O3 e/ N3 e. B: ~如果mysql -u user_name test工作但是mysql -u user_name other_db_name
. U1 i2 b, l3 l+ {* J$ u4 B$ V" E不工作,对other_db_name,你在db表中没有没有一个条目列出。
. ~3 ^2 Y ]3 v' H( j7 }3 n. c' D当在服务器机器上执行mysql -u user_name db_name时,它工作,但是在其
) {) K$ p! `3 u5 ?) v, {+ j它客户机器上执行mysql -h host_name -u user_name db_name时,它却不工作,
+ n- B' ?2 r, Z: d! }5 {你没有把客户机器列在user表或db表中。
% s/ q1 h( \9 f: z如果你不能弄明白你为什么得到Access denied,从user表中删除所有Host ; v6 E* r$ ]; Y
包含通配符值的条目(包含“%”或“_”的条目)。一个很普遍的错误是插入用 , w" R9 Q( h5 k( v
Host='%'和User='some user'插入一个新条目,认为这将允许你指定localhost
e/ K* p& I. q7 Z) R从同一台机器进行连接。它不工作的原因是缺省权限包括一个有Host='localhost'
: W# g0 `' O3 p0 N! i, l$ ^和User=''的条目,因为那个条目一个比'%'更具体的Host值'localhost',当从 5 }+ e1 N6 o$ p; ]
localhost连接时,它用于指向新条目!正确的步骤是插入Host='localhost'和
3 `1 g0 q" k2 g' S! G1 pUser='some_user'的第2个条目,或删除Host='localhost'和User=''条目。 ' t5 V* x4 d* X. L
如果你得到下列错误,你可以有一个与db或host表有关的问题:
0 Z f% w0 E% R' @6 S: c0 D( ZAccess to database denied
$ q) U5 L% w) Q; T
% n; E; \, o9 U7 ?- ~- C" \3 k如果从db表中选择了在Host列有空值的条目,保证在host表中有一个或多
) s" u5 O$ s0 \个相应的条目,指定运用db表中的哪些主机。如果在使用SQL命令SELECT ...
* s3 D2 i% T4 ~- S' wINTO OUTFILE或LOAD DATA INFILE时,你得到错误,在user表中的你的条目可 / k( f6 j& _, O m
能启用file权限。
: y- w) t) d) {" g# o
4 X0 x) `1 p: C/ |; h记住,客户程序将使用在配置文件或环境变量被指定了的连接参数。如果
$ ^# Y, a% ?3 M3 ^3 }6 X. o当你不在命令行上指定他们时,一个客户似乎正在发送错误的缺省连接参数, 0 z1 O, D% K% l' k
检查你的环境和在你的主目录下的“.my.cnf”文件。你也可以检查系统范围
+ e$ l" ~/ f& k$ G# v的MySQL配置文件,尽管更不可能将在那里指定那个客户的连接参数。如果当
( L) X9 ^6 w3 a) S3 l+ j你没有任何选项运行一个客户时,你得到Access denied,确认你没在任何选 $ f* l u4 E0 M3 j% c6 Q7 p; [
项文件里指定一个旧的口令!见4.15.4 选项文件。 1 {6 |: g6 c! M0 T, K
如果任何其它事情失败,用调试选项(例如,--debug=d,general,query) " {8 j% r* {3 q9 S: X2 B7 l
启动mysqld守护进程。这将打印有关尝试连接的主机和用户信息,和发出的每
4 }$ y2 E" H; N3 e# ^个命令的信息。见G.1 调试一个MySQL服务器。
2 X5 t: o5 V9 G9 o: _ y如果你有任何与MySQL授权表的其它问题,而且觉得你必须邮寄这个问题
) l+ z ?7 V$ Q; M/ v: p5 W到邮寄表,总是提供一个MySQL授权表的倾倒副本(dump)。你可用mysqldump * h: o1 x, B. H1 W5 I5 X
mysql命令倾倒数据库表。象平时一样,用mysqlbug脚本邮寄你的问题。在一 # c6 S# W2 L1 S
些情况下你可能用--skip-grant-tables重启mysqld以便能运行mysqldump。 ! ]* ~! ^ B, Z6 q* e! u. l0 D
怎样使MySQL安全以对抗解密高手 8 B" q! \+ G3 d# K- O, }1 x# m8 M& i6 e
当你连接一个MySQL服务器时,你通常应该使用一个口令。口令不以明文
0 p* `/ y7 D4 Z在连接上传输。
0 F) X. E v' ~. w9 F" `. z
0 C, k1 `5 C* ^( H) ^所有其它信息作为能被任何人读懂的文本被传输。如果你担心这个,你可 8 c& o+ A' h( c, y
使用压缩协议(MySQL3.22和以上版本)使事情变得更难。甚至为了使一切更安全
* S$ f1 l' \% \( J+ n" Z. l4 b,你应该安装ssh(见http://www.cs.hut.fi/ssh)。用它,你能在一个MySQL服
5 f- ^4 L9 {5 y/ @0 O$ R. m1 P- F务器与一个MySQL客户之间得到一个加密的TCP/IP连接。
6 V' z2 ]0 G! n+ z' _, e* ?9 ]3 G
) U! d8 Y% S* G) d) y9 E' _为了使一个MySQL系统安全,强烈要求你考虑下列建议:
$ `. I+ j$ N$ ~$ }! m6 K; _$ P8 }' n2 i3 B$ B# P+ H
对所有MySQL用户使用口令。记住,如果other_user没有口令,任何人能简
0 ]. |8 r3 \- Y, d L" p% ]* _单地用mysql -u other_user db_name作为任何其它的人登录。对客户机/服务器
& w) z6 {( S# t, }! O* K, g应用程序,客户可以指定任何用户名是常见的做法。在你运行它以前,你可以通 ; B' F2 F9 J4 ]8 k" V
过编辑mysql_install_db脚本改变所有用户的口令,或仅仅MySQL root的口令, & m0 D' l+ J/ c8 L. q7 v' J
象这样:
5 ]( y `5 L3 \! Q& Wshell> mysql -u root mysql 4 d. [" k0 `0 \2 U
mysql> UPDATE user SET Password=PASSWORD('new_password')
. I5 g+ k: `! PWHERE user='root'; * c* h1 Q. T8 D, Q2 P' [
mysql> FLUSH PRIVILEGES; V9 W9 _% Z+ A( ]1 Z* e
7 A. o: h. E! \2 q5 x9 Z
不要作为Unix的root用户运行MySQL守护进程。mysqld能以任何用户运行, 5 X: [$ _$ U8 Z
你也可以创造一个新的Unix用户mysql使一切更安全。如果你作为其它Unix用户 9 T8 }3 i0 N% ?+ C/ s9 `) u- N
运行mysqld,你不需要改变在user表中的root用户名,因为MySQL用户名与Unix
& u9 ]$ t7 ]3 s" s% @* ]用户名没关系。你可以作为其它Unix用户编辑mysql.server启动脚本mysqld。 8 i4 s% k- K: x
通常这用su命令完成。对于更多的细节,见18.8 怎样作为一个一般用户运行
' v$ v% w r6 \0 {5 kMySQL。
7 @& |; t# f$ b, ~- o如果你把一个Unix root用户口令放在mysql.server脚本中,确保这个脚本
* L9 v c9 \# I) `只能对root是可读的。
# L7 Z; P1 b- N+ w) Z2 Q5 n检查那个运行mysqld的Unix用户是唯一的在数据库目录下有读/写权限的用 ! `' A" T; z% E/ J, O
户。 - i, O, x( T6 S9 b
不要把process权限给所有用户。mysqladmin processlist的输出显示出当
# q# J, V: h. z1 A2 h前执行的查询正文,如果另外的用户发出一个UPDATE user SET password=
% T! Q1 v( z) _7 _& r0 t$ z4 s+ ZPASSWORD('not_secure')查询,被允许执行那个命令的任何用户可能看得到。
! f, Y' S1 Y7 D+ d2 R; ^mysqld为有process权限的用户保留一个额外的连接, 以便一个MySQL root用
6 x% h9 f* J& c/ w+ h户能登录并检查,即使所有的正常连接在使用。 6 j$ c! D1 \3 L$ {6 o( Y% U) j
不要把file权限给所有的用户。有这权限的任何用户能在拥有mysqld守护 " S+ K0 O, m0 L4 x$ F
进程权限的文件系统那里写一个文件!为了使这更安全一些,用SELECT ...
c+ d1 c6 _1 K. _9 O5 bINTO OUTFILE生成的所有文件对每个人是可读的,并且你不能覆盖已经存在的 ; d8 c& F/ F1 t* Y& |
文件。file权限也可以被用来读取任何作为运行服务器的Unix用户可存取的文
8 [* v0 O: ~! A4 F8 W1 U件。这可能被滥用,例如,通过使用LOAD DATA装载“/etc/passwd”进一个数
* R3 R6 p! E/ T据库表,然后它能用SELECT被读入。 5 i$ }7 e2 o }* s
如果你不信任你的DNS,你应该在授权表中使用IP数字而不是主机名。原则 . b1 B- T2 h: Y+ ?
上讲,--secure选项对mysqld应该使主机名更安全。在任何情况下,你应该非常 : i3 W$ a+ k; h$ e$ ]+ @
小心地使用包含通配符的主机名! + g4 }' B, s e/ m* d5 m5 Q
下列mysqld选项影响安全: " B( Y0 S6 J p: F8 v
) L& z9 V% ^& O% _3 T5 L
--secure
+ _+ p' }# r0 A& w由gethostbyname()系统调用返回的IP数字被检查,确保他们解析回到原来 / j: ~. y. f) h
的主机名。这对某些外人通过模仿其它主机获得存取权限变得更难。这个选项也
+ ~: L+ W4 L+ V- L" R& i增加一些聪明的主机名检查。在MySQL3.21里,选择缺省是关掉的,因为它有时
% u7 `' a a1 F' b# i4 r8 S0 D4 o它花很长时间执行反向解析。MySQL 3.22缓存主机名并缺省地启用了这个选项。 & r! R7 H* m7 E6 ?, z ^9 G
--skip-grant-tables 9 Z6 O2 \. Q z/ o6 [* l7 ]6 p
这个选项导致服务器根本不使用权限系统。这给每个人以完全存取所有的数 ; y3 {- W: @" b( E& i" R- q9 q
据库的权力!(通过执行mysqladmin reload,你能告诉一个正在运行的服务器
: H% K' M- d: c+ e再次开始使用授权表。) # o- T1 ]* D5 d3 j5 g
--skip-name-resolve
, g: i7 c4 C( W( D& d1 y# _7 t# j主机名不被解析。所有在授权表的Host的列值必须是IP数字或localhost。
1 v3 @: S2 H& z8 k: R3 C9 I--skip-networking , @ }& {3 W& c2 p" y2 S1 n$ d
在网络上不允许TCP/IP连接。所有到mysqld的连接必须经由Unix套接字进
, Y; A+ N* }0 ?, o' b/ C4 _行。这个选项对使用MIT-pthreads的系统是不合适的,因为MIT-pthreads包不
: N7 B5 f) w) P u3 G支持Unix套接字。 |
|