为应用建立了rnd的帐号,专门为他们查询线上数据库用的,当然,只有他们上了生产网络以后才能连上数据库,安全方面我们还是很注意的,呵呵。 
授权的语句如下: 
grant select on armory.* to rnd; 
flush privileges; 

select查询数据没有问题,但是有的用户有了更多的需求,他想把数据导出来,简单的处理的话,可以用select into outfile导出来。自己指定字段的分隔,行分隔等等。 
但是用户一查询就报:access deny的错误,权限不对。 
rnd@localhost : armory 09:26:31> select * into outfile ‘/tmp/1.txt’ from os limit 5; 
ERROR 1045 (28000): Access denied for user ‘rnd’@'%’ (using password: NO) 
郁闷的是MySQL没有说缺少了那个权限。 

在本机测试了一下, 
grant all on armory.* to rnd; 
flush privileges; 
给rnd所有的权限以后,还是报权限错误。这个就奇怪了,所有的权限都给它了,还报错?不可理喻阿。 
实在搞不定,最后让用户: 
mysql -urnd -p -e ‘select * from os limit 5;’ >1.txt 
的变通方法。 

一直被这个纠结着,突然后来有一天,查询了一下MySQL的文档,找到是file的权限没有加上去,但是当时MySQL对应的库的所有权限我都加上去了阿。灵光一闪,file是全局的权限,在MySQL中对单个库是没有这个权限概念的,所以就算我把库上的所有权限给了rnd,file的权限其实还是没有附权给它的。不信的话,我们这就试试: 
root@localhost : (none) 09:55:14> grant file on armory.* to rnd; 
ERROR 1221 (HY000): Incorrect usage of DB GRANT and GLOBAL PRIVILEGES 
果然,File权限是GLOBAL权限,不能附权给数据库。 
GLOBAL FILE附权以后 
root@localhost : mysql 09:58:21> grant file on *.* to rnd; 
Query OK, 0 rows affected (0.00 sec) 
select查询就可以执行了: 
rnd@localhost : armory 10:00:42> select * into outfile ‘/tmp/1.txt’ from os limit 5; 
Query OK, 5 rows affected (0.00 sec) 

其实MySQL的权限可能比较拗,让我们一下子适应不过来。MySQL的权限可以精细到列,权限判断是根据GLOBAL,DB,TABLE,COLUMN来授权的,可以简单的理解为他们对应到mysql库中的四个表:user,db,tables_priv,columns_priv这几个表。当然,MySQL没有这么简单拉。有兴趣的话可以好好看一下MySQL的reference或者其他介绍。举个例子: 
rnd@localhost : armory 10:00:43> show grants for rnd; 
+————————————————-+ 
| Grants for rnd@%                                | 
+————————————————-+ 
| GRANT FILE ON *.* TO ‘rnd’@'%’                  | 
| GRANT ALL PRIVILEGES ON `armory`.* TO ‘rnd’@'%’ | 
+————————————————-+ 
2 rows in set (0.00 sec) 
grant对同一个用户就分了两行,分别对应着user和db里面的两行: 
root@localhost : mysql 10:18:34> select * from mysql.user where user=’rnd’\G 
*************************** 1. row *************************** 
Host: % 
User: rnd 
Password: 
Select_priv: N 
Insert_priv: N 
Update_priv: N 
Delete_priv: N 
Create_priv: N 
Drop_priv: N 
Reload_priv: N 
Shutdown_priv: N 
Process_priv: N 
File_priv: Y 
Grant_priv: N 
References_priv: N 
Index_priv: N 
Alter_priv: N 
Show_db_priv: N 
Super_priv: N 
Create_tmp_table_priv: N 
Lock_tables_priv: N 
Execute_priv: N 
Repl_slave_priv: N 
Repl_client_priv: N 
Create_view_priv: N 
Show_view_priv: N 
Create_routine_priv: N 
Alter_routine_priv: N 
Create_user_priv: N 
Event_priv: N 
Trigger_priv: N 
ssl_type: 
ssl_cipher: 
x509_issuer: 
x509_subject: 
max_questions: 0 
max_updates: 0 
max_connections: 0 
max_user_connections: 0 
1 row in set (0.00 sec) 

root@localhost : mysql 10:18:41> select * from mysql.db where user=’rnd’\G 
*************************** 1. row *************************** 
Host: % 
Db: armory 
User: rnd 
Select_priv: Y 
Insert_priv: Y 
Update_priv: Y 
Delete_priv: Y 
Create_priv: Y 
Drop_priv: Y 
Grant_priv: N 
References_priv: Y 
Index_priv: Y 
Alter_priv: Y 
Create_tmp_table_priv: Y 
Lock_tables_priv: Y 
Create_view_priv: Y 
Show_view_priv: Y 
Create_routine_priv: Y 
Alter_routine_priv: Y 
Execute_priv: Y 
Event_priv: Y 
Trigger_priv: Y 
1 row in set (0.00 sec) 
MySQL的权限检查也是通过检查这两个表来进行判断的。 

附上tables_priv和columns_priv的两个表的字段,和user和db还是有点不同的,用到了set类型。 
root@localhost : mysql 10:18:58> desc tables_priv; 
+————-+———————————————————————————————————————————–+——+—–+——————-+—————————–+ 
| Field       | Type                                                                                                                              | Null | Key | Default           | Extra                       | 
+————-+———————————————————————————————————————————–+——+—–+——————-+—————————–+ 
| Host        | char(60)                                                                                                                          | NO   | PRI |                   |                             | 
| Db          | char(64)                                                                                                                          | NO   | PRI |                   |                             | 
| User        | char(16)                                                                                                                          | NO   | PRI |                   |                             | 
| Table_name  | char(64)                                                                                                                          | NO   | PRI |                   |                             | 
| Grantor     | char(77)                                                                                                                          | NO   | MUL |                   |                             | 
| Timestamp   | timestamp                                                                                                                         | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | 
| Table_priv  | set(‘Select’,'Insert’,'Update’,'Delete’,'Create’,'Drop’,'Grant’,'References’,'Index’,'Alter’,'Create View’,'Show view’,'Trigger’) | NO   |     |                   |                             | 
| Column_priv | set(‘Select’,'Insert’,'Update’,'References’)                                                                                      | NO   |     |                   |                             | 
+————-+———————————————————————————————————————————–+——+—–+——————-+—————————–+ 
8 rows in set (0.00 sec) 

root@localhost : mysql 10:21:24> desc columns_priv; 
+————-+———————————————-+——+—–+——————-+—————————–+ 
| Field       | Type                                         | Null | Key | Default           | Extra                       | 
+————-+———————————————-+——+—–+——————-+—————————–+ 
| Host        | char(60)                                     | NO   | PRI |                   |                             | 
| Db          | char(64)                                     | NO   | PRI |                   |                             | 
| User        | char(16)                                     | NO   | PRI |                   |                             | 
| Table_name  | char(64)                                     | NO   | PRI |                   |                             | 
| Column_name | char(64)                                     | NO   | PRI |                   |                             | 
| Timestamp   | timestamp                                    | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | 
| Column_priv | set(‘Select’,'Insert’,'Update’,'References’) | NO   |     |                   |                             | 
+————-+———————————————-+——+—–+——————-+—————————–+ 
7 rows in set (0.00 sec) 

may your success. 


------------------------------------- 
我理清是什么问题了。 
在red hat系列的linux中selinux对哪些daemon可以进行怎么样的操作是有限制的,mysql的select into outfile的命令是mysql的daemon来负责写文件操作的。写文件之前当然要具有写文件的权限。而selinux对这个权限做了限制。如果selinux是关闭的吧,这个命令执行是没有问题的 
mysql> select user from user into outfile '/home/test.txt'; 
Query OK, 2 rows affected (0.02 sec) 
当时selinux开启时 
selinux对mysql的守护进程mysqld进行了限制。 
mysql> select user from user into outfile '/home/test.txt'; 
ERROR 1 (HY000): Can't create/write to file '/home/test.txt' (Errcode: 13)  
出现了没有权限写的error。 
解决方法,可以关闭selinux。 
可以在/etc/selinux中找到config 
root用户, 
shell>vi /etc/selinux/config 

# This file controls the state of SELinux on the system. 
# SELINUX= can take one of these three values: 
# enforcing - SELinux security policy is enforced. 
# permissive - SELinux prints warnings instead of enforcing. 
# disabled - SELinux is fully disabled. 
SELINUX=enforcing 

修改SELINUX=disabled关闭selinux就可以了,这个问题就可以解决了。 
不过全部关闭SELINUX有带来一些安全问题。 
当然也可以,单独给mysql的守护进程权限, 
shell>getsebool -a可以查看当前的对系统一系列守护进程的权限情况。 

lpd_disable_trans --> off 
mail_read_content --> off 
mailman_mail_disable_trans --> off 
mdadm_disable_trans --> off 
mozilla_read_content --> off 
mysqld_disable_trans --> off 
nagios_disable_trans --> off 
named_disable_trans --> off 
named_write_master_zones --> off 
nfs_export_all_ro --> on 
nfs_export_all_rw --> on 
nfsd_disable_trans --> off 
nmbd_disable_trans --> off 
nrpe_disable_trans --> off 

shell>setsebool -P mysqld_disable_trans=1 
开启对mysql守护进程的权限,这样 
mysql> select user from user into outfile '/home/test.txt'; 
写入到自定义的目录就没有问题了。 
-P表示 是永久性设置,否则重启之后又恢复预设值。 
getsebool setsebool命令在root用户下有权限。 

除了对selinux的权限,当然首先要保证该目录拥有读写权限。 


在ubuntu下 ,可以对AppArmor(/etc/apparmor.d/usr.sbin.mysqld) 修改,类似selinux。 
添加/etc/squid/lists/eighties.txt w,类似。 

--------------------------------------------- 


root用户登录下: 
grant file on *.* to webgametest@10.3.18.158; 

改为生成在tmp文件夹下。