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

我试图使用 MySQLSELECTINTOOUTFILE 语句将表的内容转储到一个 csv 文件中。如果我这样做:

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

outfile.csv will be created on the server in the same directory this database's files are stored in.

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

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。

159207 次浏览

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

提供要写入的/data 目录的完整路径。

I know you said that you tried already setting permissions to 777, but as I have an evidence that for me it was a permission issue I'm posting what I exactly run hoping it can help. Here is my experience:

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 $

有些事情可以尝试:

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

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

最近的 Ubuntu 服务器版本(比如10.04)默认情况下可能处于强制执行模式。您可以像下面这样执行 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 包含在强制模式中,那么它可能就是拒绝写的那个。条目也将在 /var/log/messages中写入,当 Appdeck 阻止写入/访问时。你能做的就是编辑 /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,**
}

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

# sudo /etc/init.d/apparmor reload

警告: 上面的更改将允许 MySQL 读写/data 目录。我们希望您已经考虑过此事的安全隐患。

Ubuntu 使用 SELinux 吗?检查它是否启用和执行。/var/log/audit.log 可能会有帮助(如果 Ubuntu 把它放在那里——那就是 RHEL/Fedora 的位置)。

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

要修改 AppArma 以允许 MySQL 访问/数据/执行以下操作:

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

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

/data/ rw,

然后做一个:

sudo /etc/init.d/apparmor restart

Another option is to disable AppArmor for mysql altogether, this is NOT RECOMMENDED:

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

别忘了重新启动仪器:

sudo /etc/init.d/apparmor restart

在我的例子中,解决方案是使目录路径中的每个目录都可读,并且可由 mysql(chmod a+rx)访问。目录仍然由命令行中的相对路径指定。

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

这个问题困扰我很长时间了。我注意到这个讨论并没有指出 RHEL/Fecora 的解决方案。我正在使用 RHEL,并且在 Ubuntu 上没有找到与 AppArmer 对应的配置文件,但是我通过使目录 PATH 中的每个目录都可读并且 mysql 可访问来解决我的问题。例如,如果创建目录/tmp,则以下两个命令使 SELECT INTO OUTFILE 能够输出。Sql 和。Sql 文件

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

如果在主目录/home/tom 中创建目录,则必须同时为/home 和/home/tom 创建目录。

MySQL 越来越愚蠢了,它试图在/tmp/data/... 下创建文件,所以你可以这样做:

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

Then try your query. This worked for me after hours of debugging the issue.

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

你可以这样做:

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

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

  • Operating system : ubuntu 12.04
  • 安装灯泡
  • 假设要保存输出文件的目录是:/var/www/csv/

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

Sudo gedit/etc/appmor.d/usr.sbin.mysqld

  • 现在文件将在编辑器中打开,请在那里添加您的目录

    /var/www/csv/* rw,

  • 同样,我已经在我的文件中添加了如下给定的图像:

enter image description here

执行下一个命令以重新启动服务:

Sudo/etc/init.d/parmor 重新启动

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

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

它成功地完成并将所有带有选定列的行写入 OUTPUT.csv 文件..。

我在 CentOs 6.7上也遇到过同样的问题 在我的例子中,所有权限都已设置,但仍然出现错误。问题是 SELinux 处于“执行”模式。

我使用 sudo setenforce 0命令将其切换为“宽容”

然后一切都解决了。