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