如何使用 SELECT INTO OUTFILE 绕过 MySQL Errcode 13?

Posted

技术标签:

【中文标题】如何使用 SELECT INTO OUTFILE 绕过 MySQL Errcode 13?【英文标题】:How can I get around MySQL Errcode 13 with SELECT INTO OUTFILE? 【发布时间】:2011-02-16 12:28:24 【问题描述】:

我正在尝试使用 mysql SELECT INTO OUTFILE 语句将表的内容转储到 csv 文件。如果我这样做:

SELECT column1, column2
INTO OUTFILE 'outfile.csv'
FIELDS TERMINATED BY ','
FROM table_name;

outfile.csv 将在服务器上与该数据库的文件存储在同一目录中创建。

但是,当我将查询更改为:

SELECT column1, column2
INTO OUTFILE '/data/outfile.csv'
FIELDS TERMINATED BY ','
FROM table_name;

我明白了:

ERROR 1 (HY000): Can't create/write to file '/data/outfile.csv' (Errcode: 13)

Errcode 13 是权限错误,但即使我将 /data 的所有权更改为 mysql:mysql 并赋予它 777 权限,我也会得到它。 MySQL 以用户“mysql”运行。

奇怪的是,我可以在 /tmp 中创建文件,而不是在我尝试过的任何其他目录中,即使设置了权限,用户 mysql 应该能够写入该目录。

这是在 Ubuntu 上运行的 MySQL 5.0.75。

【问题讨论】:

看到 13 是系统错误,这可能不是它,但是有一个 mySQL 设置将 INTO OUTFILE 限制为一个目录:dev.mysql.com/doc/refman/5.0/en/… 是否设置为@987654325 可能值得快速查看@. 该变量在我的安装中是空白的,根据该文档,这意味着我的输出目录不应受到限制。 【参考方案1】:

您需要提供绝对路径,而不是相对路径。

提供您尝试写入的 /data 目录的完整路径。

【讨论】:

这对我来说似乎是一条绝对路径。不是吗? 以 mysql 用户身份尝试此操作,以验证您是否可以在 mysql 之外创建文件:touch /data/outfile.csv 首先我做不到,因为mysql用户的shell设置为/bin/false,所以不能用mysql登录。只是为了确保这不会导致问题,我将 mysql 的 shell 设置为 /bin/bash,su'd 到该用户并触摸 /data 中的一个文件。文件创建成功,归mysql所有。 您可以 su 到一个帐户,即使它使用“禁用”外壳之一:su --shell=/bin/sh nameofaccount 谢谢,我不知道。【参考方案2】:

我知道您说过您已经尝试将权限设置为 777,但由于我有证据表明对我来说这是一个权限问题,因此我发布了我正在运行的内容,希望它可以提供帮助。这是我的经验:

tmp $ pwd
/Users/username/tmp
tmp $ mkdir bkptest
tmp $ mysqldump -u root -T bkptest bkptest
mysqldump: Got error: 1: Can't create/write to file '/Users/username/tmp/bkptest/people.txt' (Errcode: 13) when executing 'SELECT INTO OUTFILE'
tmp $ chmod a+rwx bkptest/
tmp $ mysqldump -u root -T bkptest bkptest
tmp $ ls bkptest/
people.sql  people.txt
tmp $ 

【讨论】:

me@server:/data$ pwd /data me@server:/data$ ls -al total 60 ... drwxrwxrwx 2 mysql mysql 4096 2010-05-06 16:27 dumptest me@server :/data$ mysqldump -u dbuser -p -T dumptest -B db_name --tables test 输入密码:mysqldump: Got error: 1: Can't create/write to file '/data/dumptest/test.txt' (Errcode : 13) 当执行 'SELECT INTO OUTFILE' me@server:/data$ sudo chmod a+rwx dumptest/ me@server:/data$ mysqldump -u dbuser -p -T dumptest -B db_name --tables test 输入密码: mysqldump:得到错误:1:(同样的错误) 哦,好吧,没有意识到 cmets 不会格式化,但仔细检查了几种不同的方式。首先使用 mysql:mysql 拥有的目标目录,然后使用我运行转储命令的用户拥有的目标目录,两种方式仍然给我相同的权限错误。 为了记录,尽管更改了 apparmor 权限,这对我有用 我尝试对 apparmor 进行修改,但没有成功。更改权限“chmod 777”对我有用!【参考方案3】:

一些尝试:

是否设置了secure_file_priv 系统变量?如果是,则必须将所有文件写入该目录。 确保文件不存在 - MySQL 只会创建新文件,不会覆盖现有文件。

【讨论】:

我也会选择secure_file_priv。如果文件已经存在,则错误信息不同(不是errcode 13)。 secure_file_priv 当前未设置,因此据我了解,这意味着我不应该受限于可以写入文件的位置。我是否误解了这一点,如果我希望能够在文件系统上的任何位置写入,是否需要将其显式设置为“/”之类的内容? 另外,我在运行查询之前检查该文件是否不存在。 感谢您的反馈。根据您的发现,我认为这些建议都不会导致您的问题。【参考方案4】:

这是哪个特定版本的 Ubuntu,这是 Ubuntu 服务器版?

最近的 Ubuntu 服务器版本(例如 10.04)附带 AppArmor 并且 MySQL 的配置文件可能默认处于强制模式。您可以通过执行sudo aa-status 来检查这一点,如下所示:

# sudo aa-status
5 profiles are loaded.
5 profiles are in enforce mode.
   /usr/lib/connman/scripts/dhclient-script
   /sbin/dhclient3
   /usr/sbin/tcpdump
   /usr/lib/NetworkManager/nm-dhcp-client.action
   /usr/sbin/mysqld
0 profiles are in complain mode.
1 processes have profiles defined.
1 processes are in enforce mode :
   /usr/sbin/mysqld (1089)
0 processes are in complain mode.

如果 mysqld 包含在强制模式中,那么它可能是拒绝写入的那个。当 AppArmor 阻止写入/访问时,条目也将写入 /var/log/messages。您可以编辑/etc/apparmor.d/usr.sbin.mysqld 并在底部附近添加/data//data/*,如下所示:

...  
/usr/sbin/mysqld    
    ...  
    /var/log/mysql/ r,  
    /var/log/mysql/* rw,  
    /var/run/mysqld/mysqld.pid w,  
    /var/run/mysqld/mysqld.sock w,  
    **/data/ r,  
    /data/* rw,**  

然后让 AppArmor 重新加载配置文件。

# sudo /etc/init.d/apparmor reload

警告:以上更改将允许 MySQL 读取和写入 /data 目录。我们希望您已经考虑过这对安全的影响。

【讨论】:

我不想指出这一点,但 App Armor 不允许这样做是有原因的。 MySQL 现在能够修改和读取 /data 文件夹中的任何内容。只是现在不要被黑客入侵。 @Serdar,随发行版分发的 AppArmor MySQL 规则集默认情况下不允许这样做。这是有道理的,因为它是全新安装的良好规则基准。我相信我们应该并且被允许修改规则集以满足安装后的需求。最初询问者的意图是允许 MySQL 写入特定目录。但是,如果上面不是很明确,请注意对这个解决方案的更多人绊脚石:警告:上面的更改将允许 MySQL 读取和写入 /data 目录。我们希望您已经考虑过这对安全的影响。 很好的答案!!!它解决了我的问题,我也试图在任何其他目录中写入。现在,我必须研究这一切是关于什么的! :) 了解这一点后,我建议其他人阅读有关 apparmor(以及命令 aa-status)的信息:en.wikipedia.org/wiki/AppArmor 在我的情况下这有帮助:/your/abs/folder/ r, /your/abs/folder/** rwk, 不要忘记在末尾加上逗号! 它可以写入/tmp。改用窗户。【参考方案5】:

Ubuntu 使用 SELinux 吗?检查它是否已启用并强制执行。 /var/log/audit/audit.log 可能会有所帮助(如果这是 Ubuntu 坚持的地方——那就是 RHEL/Fedora 的位置)。

【讨论】:

【参考方案6】:

Ubuntu 使用 AppArmor,这就是阻止您访问 /data/ 的原因。 Fedora 使用 selinux,这可以防止在 RHEL/Fedora/CentOS 机器上发生这种情况。

要修改 AppArmor 以允许 MySQL 访问 /data/,请执行以下操作:

sudo gedit /etc/apparmor.d/usr.sbin.mysqld

将此行添加到目录列表中的任何位置:

/data/ rw,

然后做一个:

sudo /etc/init.d/apparmor restart

另一种选择是完全禁用 mysql 的 AppArmor,这是不推荐

sudo mv /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/

别忘了重启apparmor:

sudo /etc/init.d/apparmor restart

【讨论】:

要真正禁用 mysql 的 apparmor,我需要这样做:cyberciti.biz/faq/ubuntu-linux-howto-disable-apparmor-commands【参考方案7】:

就我而言,解决方案是使目录路径中的每个目录都可以被mysql (chmod a+rx) 读取和访问。该目录仍由其在命令行中的相对路径指定。

chmod a+rx /tmp
chmod a+rx /tmp/migration
etc.

【讨论】:

【参考方案8】:

这个问题困扰了我很久。我注意到这个讨论没有指出关于 RHEL/Fecora 的解决方案。我正在使用 RHEL,但在 Ubuntu 上找不到与 AppArmer 对应的配置文件,但我通过使目录 PATH 中的每个目录都可以被 mysql 读取和访问来解决我的问题。例如,如果您创建一个目录 /tmp,以下两个命令使 SELECT INTO OUTFILE 能够输出 .sql AND .sql 文件

chown mysql:mysql /tmp
chmod a+rx /tmp

如果您在主目录 /home/tom 中创建目录,则必须对 /home 和 /home/tom 都执行此操作。

【讨论】:

以 /tmp 为例并不是一个好主意,而且您确实不想更改 /tmp 目录的所有权(在大多数情况下)。 更改 /tmp 的所有权是不好的,但是在 /tmp 和 chown mysql:mysql 中创建一个临时文件夹解决了我的问题【参考方案9】:

MySQL 在这里变得愚蠢。它会尝试在 /tmp/data/.... 下创建文件。所以您可以执行以下操作:

mkdir /tmp/data
mount --bind /data /tmp/data

然后尝试您的查询。经过数小时调试问题后,这对我有用。

【讨论】:

我最喜欢这个答案。这很简单,它很有效,而且它不需要你使用 apparmor。由于已完成所有缓冲,使用管道的另一种方法不适用于大型导出。【参考方案10】:

我刚刚遇到了同样的问题。我的问题是我试图转储到的目录没有 mysqld 进程的写权限。初始 sql 转储会写出,但 csv/txt 文件的写入会失败。看起来 sql 转储以当前用户身份运行,而到 csv/txt 的转换以运行 mysqld 的用户身份运行。所以目录需要两个用户的写权限。

【讨论】:

【参考方案11】:

你可以这样做:

mysql -u USERNAME --password=PASSWORD --database=DATABASE --execute='SELECT `FIELD`, `FIELD` FROM `TABLE` LIMIT 0, 10000 ' -X > file.xml

【讨论】:

谢谢!是否可以将输出控制为 CSV?【参考方案12】:

我有同样的问题,我通过以下步骤解决了这个问题:

操作系统:ubuntu 12.04 灯已安装 假设你保存输出文件的目录是:/var/www/csv/

在终端上执行以下命令并使用 gedit 编辑器编辑此文件以将您的目录添加到输出文件。

sudo gedit /etc/apparmor.d/usr.sbin.mysqld

现在文件将在编辑器中打开,请在此处添加您的目录

/var/www/csv/* rw,

同样,我已在文件中添加,如下图所示:

执行下一条命令重启服务:

sudo /etc/init.d/apparmor 重启

例如,我在 phpmyadmin 查询生成器中执行以下查询以在 csv 文件中输出数据

SELECT colName1, colName2,colName3
INTO OUTFILE '/var/www/csv/OUTFILE.csv'
FIELDS TERMINATED BY ','
FROM tableName;

它已成功完成并将所有包含选定列的行写入 OUTPUT.csv 文件...

【讨论】:

【参考方案13】:

我在 CentOs 6.7 上遇到了同样的问题 在我的情况下,所有权限都已设置,但仍然发生错误。问题是 SE Linux 处于“强制”模式。

我使用命令 sudo setenforce 0 将其切换为“允许”

然后一切都为我解决了。

【讨论】:

以上是关于如何使用 SELECT INTO OUTFILE 绕过 MySQL Errcode 13?的主要内容,如果未能解决你的问题,请参考以下文章