如何使用 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?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL SELECT INTO OUTFILE 到不同的服务器?

Mysql select into outfile 命令

MySQL 如何使用 INTO OUTFILE 附加到文件?

Mysql 使用 select into outfile

select into outfile

select into outfile