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