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