tags:

views:

747

answers:

6

I am trying to dump the contents of a table to a csv file using a MySQL SELECT INTO OUTFILE statement. If I do:

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.

However, when I change my query to:

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

I get:

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

Errcode 13 is a permissions error, but I get it even if I change ownership of /data to mysql:mysql and give it 777 permissions. MySQL is running as user "mysql".

Strangely I can create the file in /tmp, just not in any other directory I've tried, even with permissions set such that user mysql should be able to write to the directory.

This is MySQL 5.0.75 running on Ubuntu.

A: 

You need to provide an absolute path, not a relative path.

Provide the full path to the /data directory you are trying to write to.

Ike Walker
That looks like an absolute path to me. Is it not?
Pekka
It is an absolute path, yes.
Ryan Olson
Try this as the mysql user to verify that you can create the file outside of mysql: `touch /data/outfile.csv`
Ike Walker
First I couldn't do it because the mysql user's shell was set to /bin/false, so I couldn't log in as mysql. Just to make sure that wasn't contributing to the problem, I set mysql's shell to /bin/bash, su'd to that user and touched a file in /data. The file was created successfully, owned by mysql.
Ryan Olson
You can su to an account even if it's using one of the "disable" shells: `su --shell=/bin/sh nameofaccount`
Marc B
Thanks, I wasn't aware of that.
Ryan Olson
+1  A: 

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 $ 
Xan
me@server:/data$ pwd/datame@server:/data$ ls -altotal 60...drwxrwxrwx 2 mysql mysql 4096 2010-05-06 16:27 dumptestme@server:/data$ mysqldump -u dbuser -p -T dumptest -B db_name --tables testEnter password: mysqldump: Got error: 1: Can't create/write to file '/data/dumptest/test.txt' (Errcode: 13) when executing 'SELECT INTO OUTFILE'me@server:/data$ sudo chmod a+rwx dumptest/me@server:/data$ mysqldump -u dbuser -p -T dumptest -B db_name --tables testEnter password: mysqldump: Got error: 1: (same error)
Ryan Olson
Oy, well, didn't realize comments wouldn't format, but double checked a few different ways. First with the target directory owned by mysql:mysql, then with the target directory owned by the user I was running the dump command as, both ways still give me the same permissions error.
Ryan Olson
+3  A: 

Some things to try:

  • is the secure_file_priv system variable set? If it is, all files must be written to that directory.
  • ensure that the file does not exist - MySQL will only create new files, not overwrite existing ones.
mdma
I would also go for secure_file_priv.If the file already exists, the error message is different (not errcode 13).
Xavier Maillard
secure_file_priv is not currently set, so as I understand it that means that I should not be limited as to where I can write files. Am I misunderstanding that and do I need to explicitly set it to something like '/' if I want to be able to write anywhere on the file system?
Ryan Olson
Also, I am checking that the file does not exist before running the query.
Ryan Olson
Thanks for the feedback. Based on your findings, I don't think either of these suggestions causes your problem.
mdma
+6  A: 

Which particular version of Ubuntu is this and is this Ubuntu Server Edition?

Recent Ubuntu Server Editions (such as 10.04) ship with AppArmor and MySQL's profile might be in enforcing mode by default. You can check this by executing sudo aa-status like so:

# 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.

If mysqld is included in enforce mode, then it is the one probably denying the write. Entries would also be written in /var/log/messages when AppArmor blocks the writes/accesses. What you can do is edit /etc/apparmor.d/usr.sbin.mysqld and add /data/ and /data/* near the bottom like so:

...
/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,

}

And then make AppArmor reload the profiles.

# sudo /etc/init.d/apparmor reload
Vin-G
This was Ubuntu 9.04, but AppArmor was denying the write. Thanks so much, this solved this for me.
Ryan Olson
happy to help :)
Vin-G
omg- thank you! been stuck on this for way too long.
therealsix
+1  A: 

Does Ubuntu use SELinux? Check to see if it's enabled and enforcing. /var/log/audit/audit.log may be helpul (if that's where Ubuntu sticks it -- that's the RHEL/Fedora location).

Charles
+2  A: 

Ubuntu uses AppArmor and that is whats preventing you from accessing /data/. Fedora uses selinux and that would prevent this on a RHEL/Fedora/CentOS machine.

To modify AppArmor to allow MySQL to access /data/ do the follow:

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

add this line anywhere in the list of directories:

/data/ rw,

then do a :

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/

Don't forget to restart apparmor:

sudo /etc/init.d/apparmor restart

Rook