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