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