如何使用 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 到不同的服务器?