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