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