¿Cómo puedo evitar MySQL Errcode 13 con SELECT INTO OUTFILE?

114

Estoy tratando de volcar el contenido de una tabla en un archivo csv usando una declaración MySQL SELECT INTO OUTFILE. Si lo hago:

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

outfile.csv se creará en el servidor en el mismo directorio en el que se almacenan los archivos de esta base de datos.

Sin embargo, cuando cambio mi consulta a:

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

Yo obtengo:

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

Errcode 13 es un error de permisos, pero lo obtengo incluso si cambio la propiedad de / data a mysql: mysql y le doy 777 permisos. MySQL se ejecuta como usuario "mysql".

Curiosamente, puedo crear el archivo en / tmp, pero no en ningún otro directorio que haya probado, incluso con los permisos establecidos de manera que el usuario mysql debería poder escribir en el directorio.

Este es MySQL 5.0.75 ejecutándose en Ubuntu.

Ryan Olson
fuente
3
Dado que el 13 es un error del sistema, probablemente no lo sea, pero hay una configuración de mySQL que limita INTO OUTFILE a un directorio: dev.mysql.com/doc/refman/5.0/en/ ... tal vez valga la pena echar un vistazo rápido si es establecido en /tmp.
Pekka
Esa variable está en blanco en mi instalación, lo que de acuerdo con ese documento significa que mis directorios de salida no deberían estar limitados.
Ryan Olson

Respuestas:

189

¿Qué versión particular de Ubuntu es esta y es esta Ubuntu Server Edition?

Las ediciones recientes de Ubuntu Server (como 10.04) se envían con AppArmor y el perfil de MySQL puede estar en modo obligatorio de forma predeterminada. Puede verificar esto ejecutando sudo aa-statusasí:

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

Si mysqld está incluido en el modo de imposición, probablemente sea el que niegue la escritura. Las entradas también se escribirán /var/log/messagescuando AppArmor bloquee las escrituras / accesos. Lo que puede hacer es editar /etc/apparmor.d/usr.sbin.mysqldy agregar /data/y /data/*cerca de la parte inferior así:

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

Y luego haga que AppArmor vuelva a cargar los perfiles.

# sudo /etc/init.d/apparmor reload

ADVERTENCIA: el cambio anterior permitirá que MySQL lea y escriba en el directorio / data. Esperamos que ya haya considerado las implicaciones de seguridad de esto.

Vin-G
fuente
2
Odio señalar esto, pero hay una razón por la que App Armor no lo permite. MySQL ahora tiene la capacidad de modificar y leer cualquier cosa en la carpeta / data. Simplemente no te dejes piratear ahora.
Ryan Ward
2
@Serdar, el conjunto de reglas de AppArmor MySQL distribuido con la distribución no lo permite de forma predeterminada . Esto tiene sentido ya que es una buena base de reglas para una instalación nueva. Creo que deberíamos modificar el conjunto de reglas para adaptarnos a nuestras necesidades después de la instalación. La intención del autor de la pregunta original era permitir que MySQL escribiera en directorios específicos. Pero si no es explícito arriba, una nota para las personas que se encuentran con esta solución: ADVERTENCIA: el cambio anterior permitirá que MySQL lea y escriba en el directorio / data. Esperamos que ya haya considerado las implicaciones de seguridad de esto.
Vin-G
1
¡¡¡GRAN RESPUESTA!!! Resolvió mi problema, también estaba tratando de escribir en cualquier otro directorio. ¡Ahora tengo que investigar de qué se trataba todo esto! :) Al enterarse de esto, recomiendo a otras personas que lean sobre apparmor (y por lo tanto, el comando aa-status): en.wikipedia.org/wiki/AppArmor
David L
1
En mi caso, esto ayudó: /your/abs/folder/ r, /your/abs/folder/** rwk, }¡no olvides incluir la coma al final!
ACV
1
funciona para escribir en / tmp. En su lugar, utilice Windows. Linux apesta
Victor Ionescu
17

Ubuntu usa AppArmor y eso es lo que le impide acceder a / data /. Fedora usa selinux y eso evitaría esto en una máquina RHEL / Fedora / CentOS.

Para modificar AppArmor para permitir que MySQL acceda a / data / haga lo siguiente:

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

agregue esta línea en cualquier lugar de la lista de directorios:

/data/ rw,

luego haz un:

sudo /etc/init.d/apparmor restart

Otra opción es deshabilitar AppArmor para mysql por completo, esto NO SE RECOMIENDA :

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

No olvide reiniciar apparmor:

sudo /etc/init.d/apparmor restart

torre
fuente
Para desactivar apparmor realidad para MySQL que tenía que hacer: cyberciti.biz/faq/ubuntu-linux-howto-disable-apparmor-commands
silver_mx
14

Sé que dijiste que ya trataste de configurar los permisos en 777, pero como tengo evidencia de que para mí fue un problema de permisos, estoy publicando lo que ejecuto exactamente con la esperanza de que pueda ayudar. Esta es mi experiencia:

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 $ 
basilikode
fuente
yo @ servidor: / datos $ pwd / datos yo @ servidor: / datos $ ls -al total 60 ... drwxrwxrwx 2 mysql mysql 4096 2010-05-06 16:27 dumptest me @ servidor: / datos $ mysqldump -u dbuser -p -T dumptest -B db_name --tables test Ingrese la contraseña: mysqldump: Obtuve el error: 1: No se puede crear / escribir en el archivo '/data/dumptest/test.txt' (Errcode: 13) al ejecutar '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 Ingresar contraseña: mysqldump: Obtuve el error: 1: ( mismo error)
Ryan Olson
Oy, bueno, no me di cuenta de que los comentarios no se formatearían, pero verifiqué varias formas diferentes. Primero con el directorio de destino propiedad de mysql: mysql, luego con el directorio de destino propiedad del usuario con el que estaba ejecutando el comando dump, ambas formas todavía me dan el mismo error de permisos.
Ryan Olson
Para que conste, esto funcionó para mí a pesar de haber cambiado los permisos de aparición
Alex
Intenté hacer modificaciones para aparecer, no funcionó. ¡Cambiar el permiso 'chmod 777' funcionó para mí!
Sudarshan_SMD
7

MySQL se está volviendo estúpido aquí. Intenta crear archivos en / tmp / data / .... Entonces, lo que puede hacer es lo siguiente:

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

Entonces prueba tu consulta. Esto funcionó para mí después de horas de depurar el problema.

vimdude
fuente
Me gusta más esta respuesta. Es fácil, funciona y no requiere que te dediques a la apariencia. La otra forma de hacerlo utilizando canalizaciones no funciona bien para grandes exportaciones debido a todo el almacenamiento en búfer que se realiza.
Chris Seline
6

Este problema me ha estado molestando durante mucho tiempo. Noté que esta discusión no señala la solución en RHEL / Fecora. Estoy usando RHEL y no encuentro los archivos de configuración correspondientes a AppArmer en Ubuntu, pero resolví mi problema haciendo que CADA directorio en el directorio PATH sea legible y accesible por mysql. Por ejemplo, si crea un directorio / tmp, los dos comandos siguientes hacen que SELECT INTO OUTFILE pueda generar el archivo .sql Y .sql

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

Si crea un directorio en su directorio personal / home / tom, debe hacerlo tanto para / home como para / home / tom.

fanchyna
fuente
3
Usar / tmp como ejemplo no es una buena idea, y realmente no desea cambiar la propiedad del directorio / tmp (en la mayoría de los casos).
sastorsl
Cambiar la propiedad de / tmp es malo, pero crear una carpeta temporal dentro de / tmp y chown mysql:mysqlresolver mi problema
Samuel Prevost
6

Puedes hacerlo :

mysql -u USERNAME --password=PASSWORD --database=DATABASE --execute='SELECT `FIELD`, `FIELD` FROM `TABLE` LIMIT 0, 10000 ' -X > file.xml
Navrattan Yadav
fuente
¡Gracias! ¿Es posible controlar la salida como CSV?
Hamman Samuel
4

Algunas cosas para probar:

  • es el secure_file_priv configurada la variable del sistema? Si es así, todos los archivos deben escribirse en ese directorio.
  • asegúrese de que el archivo no exista: MySQL solo creará archivos nuevos, no sobrescribirá los existentes.
mdma
fuente
1
También optaría por secure_file_priv. Si el archivo ya existe, el mensaje de error es diferente (no errcode 13).
Xavier Maillard
secure_file_priv no está configurado actualmente, por lo que tengo entendido, eso significa que no debería limitarme a dónde puedo escribir archivos. ¿Estoy entendiendo mal eso y necesito establecerlo explícitamente en algo como '/' si quiero poder escribir en cualquier lugar del sistema de archivos?
Ryan Olson
Además, estoy comprobando que el archivo no existe antes de ejecutar la consulta.
Ryan Olson
Gracias por la respuesta. Según sus hallazgos, no creo que ninguna de estas sugerencias cause su problema.
mdma
3

Tengo el mismo problema y solucioné este problema siguiendo los pasos:

  • Sistema operativo: ubuntu 12.04
  • lámpara instalada
  • suponga que su directorio para guardar el archivo de salida es: / var / www / csv /

Ejecute el siguiente comando en la terminal y edite este archivo usando el editor gedit para agregar su directorio al archivo de salida.

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

  • ahora el archivo se abrirá en el editor, agregue su directorio allí

    / var / www / csv / * rw,

  • Asimismo, he agregado en mi archivo, como la siguiente imagen dada:

ingrese la descripción de la imagen aquí

Ejecute el siguiente comando para reiniciar los servicios:

sudo /etc/init.d/apparmor reiniciar

Por ejemplo, ejecuto la siguiente consulta en el generador de consultas phpmyadmin para generar datos en un archivo csv

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

Se hizo con éxito y escribió todas las filas con columnas seleccionadas en el archivo OUTPUT.csv ...

Soleado SM
fuente
2

En mi caso, la solución fue hacer que cada directorio en la ruta del directorio fuera legible y accesible por mysql( chmod a+rx). El directorio todavía estaba especificado por su ruta relativa en la línea de comando.

chmod a+rx /tmp
chmod a+rx /tmp/migration
etc.
Alsciende
fuente
2

Me encontré con el mismo problema. Mi problema fue que el directorio en el que estaba tratando de volcar no tenía permiso de escritura para el proceso mysqld. El volcado de sql inicial se escribiría, pero la escritura del archivo csv / txt fallaría. Parece que el volcado de sql se ejecuta como el usuario actual y la conversión a csv / txt se ejecuta como el usuario que está ejecutando mysqld. Entonces, el directorio necesita permisos de escritura para ambos usuarios.

Matthew McMillan
fuente
1

Debe proporcionar una ruta absoluta, no una ruta relativa.

Proporcione la ruta completa al directorio / data en el que está intentando escribir.

Ike Walker
fuente
Eso me parece un camino absoluto. ¿No lo es?
Pekka
2
Pruebe esto como usuario de mysql para verificar que puede crear el archivo fuera de mysql:touch /data/outfile.csv
Ike Walker
1
Primero no pude hacerlo porque el shell del usuario de mysql estaba configurado en / bin / false, por lo que no pude iniciar sesión como mysql. Solo para asegurarme de que eso no estaba contribuyendo al problema, configuré el shell de mysql en / bin / bash, utilicé a ese usuario y toqué un archivo en / data. El archivo fue creado con éxito, propiedad de mysql.
Ryan Olson
3
Puede abrir una cuenta incluso si está usando uno de los shells "deshabilitar": su --shell=/bin/sh nameofaccount
Marc B
Gracias, no estaba al tanto de eso.
Ryan Olson
1

¿Ubuntu usa SELinux? Verifique si está habilitado y cumpliendo. /var/log/audit/audit.log puede ser útil (si ahí es donde Ubuntu lo pega, esa es la ubicación de RHEL / Fedora).

Charles
fuente
0

Tuve el mismo problema en CentOs 6.7. En mi caso, se establecieron todos los permisos y aún así se produjo el error. El problema era que el SE Linux estaba en modo "imponiendo".

Lo cambié a "permisivo" usando el comando sudo setenforce 0

Entonces todo salió bien para mí.

Stefan Bicher
fuente