為應用建立了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文件夾下。