Wie kann ich MySQL Errcode 13 mit SELECT INTO OUTFILE umgehen?


114

Ich versuche, den Inhalt einer Tabelle mit einer MySQL SELECT INTO OUTFILE-Anweisung in eine CSV-Datei zu kopieren. Wenn ich mache:

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

outfile.csv wird auf dem Server in demselben Verzeichnis erstellt, in dem die Dateien dieser Datenbank gespeichert sind.

Wenn ich jedoch meine Abfrage in Folgendes ändere:

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

Ich bekomme:

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

Errcode 13 ist ein Berechtigungsfehler, aber ich erhalte ihn auch dann, wenn ich den Besitz von / data in mysql: mysql ändere und ihm 777 Berechtigungen erteile. MySQL läuft als Benutzer "mysql".

Seltsamerweise kann ich die Datei in / tmp erstellen, nur in keinem anderen Verzeichnis, das ich ausprobiert habe, selbst wenn die Berechtigungen so festgelegt sind, dass der Benutzer mysql in das Verzeichnis schreiben kann.

Dies ist MySQL 5.0.75, das unter Ubuntu ausgeführt wird.


3
Da es sich bei der 13 um einen Systemfehler handelt, ist dies wahrscheinlich nicht der Fall , aber es gibt eine mySQL-Einstellung, die INTO OUTFILE auf ein Verzeichnis beschränkt: dev.mysql.com/doc/refman/5.0/en/… ist möglicherweise einen kurzen Blick wert, ob dies der Fall ist auf einstellen /tmp.
Pekka

Diese Variable ist in meiner Installation leer, was laut diesem Dokument bedeutet, dass meine Ausgabeverzeichnisse nicht eingeschränkt werden sollten.
Ryan Olson

Antworten:


189

Welche spezielle Version von Ubuntu ist das und ist das Ubuntu Server Edition?

Neuere Ubuntu Server-Editionen (z. B. 10.04), die mit AppArmor und MySQL-Profil geliefert werden, befinden sich möglicherweise standardmäßig im Erzwingungsmodus. Sie können dies überprüfen, indem Sie Folgendes ausführen 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.

Wenn mysqld im Durchsetzungsmodus enthalten ist, ist es derjenige, der wahrscheinlich das Schreiben verweigert. Einträge werden auch geschrieben, /var/log/messageswenn AppArmor die Schreibvorgänge / Zugriffe blockiert. Was Sie tun können, ist bearbeiten /etc/apparmor.d/usr.sbin.mysqldund hinzufügen /data/und /data/*in der Nähe des unteren wie folgt :

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

Lassen Sie AppArmor dann die Profile neu laden.

# sudo /etc/init.d/apparmor reload

WARNUNG: Mit der obigen Änderung kann MySQL in das Verzeichnis / data lesen und schreiben. Wir hoffen, Sie haben die Auswirkungen auf die Sicherheit bereits berücksichtigt.


2
Ich hasse es, darauf hinzuweisen, aber es gibt einen Grund, warum App Armor dies nicht zulässt. MySQL kann jetzt alles im Ordner / data ändern und lesen. Lass dich jetzt einfach nicht hacken.
Ryan Ward

2
@Serdar, Der mit der Distribution verteilte AppArmor MySQL-Regelsatz lässt dies standardmäßig nicht zu . Dies ist sinnvoll, da dies eine gute Grundlage für Regeln für eine Neuinstallation ist. Ich glaube, wir sollten und dürfen die Regelsätze nach der Installation an unsere Bedürfnisse anpassen. Es war die Absicht des ursprünglichen Fragestellers, MySQL das Schreiben in die spezifischen Verzeichnisse zu ermöglichen. Wenn dies oben nicht ohne weiteres explizit angegeben ist, ein Hinweis für weitere Personen, die über diese Lösung stolpern: WARNUNG: Mit der obigen Änderung kann MySQL in das Verzeichnis / data lesen und schreiben. Wir hoffen, Sie haben die Auswirkungen auf die Sicherheit bereits berücksichtigt.
Vin-G

1
GUTE ANTWORT!!! Es löste mein Problem, ich versuchte auch, in ein anderes Verzeichnis zu schreiben. Jetzt muss ich recherchieren, worum es ging! :) Als ich davon erfuhr, empfehle ich anderen Leuten, über Apparmor (und damit den Befehl aa-status) zu lesen: en.wikipedia.org/wiki/AppArmor
David L

1
In meinem Fall hat dies geholfen: /your/abs/folder/ r, /your/abs/folder/** rwk, }Vergessen Sie nicht, das Komma am Ende einzufügen!
ACV

1
es funktioniert, in / tmp zu schreiben. Verwenden Sie stattdessen Windows. Linux saugt
Victor Ionescu

17

Ubuntu verwendet AppArmor und das hindert Sie daran, auf / data / zuzugreifen. Fedora verwendet Selinux und dies würde dies auf einem RHEL / Fedora / CentOS-Computer verhindern.

Um AppArmor so zu ändern, dass MySQL auf / data / zugreifen kann, gehen Sie wie folgt vor:

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

Fügen Sie diese Zeile an einer beliebigen Stelle in der Liste der Verzeichnisse hinzu:

/data/ rw,

dann mache ein:

sudo /etc/init.d/apparmor restart

Eine weitere Option ist das Deaktivieren von AppArmor für MySQL. Dies wird NICHT EMPFOHLEN :

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

Vergessen Sie nicht, apparmor neu zu starten:

sudo /etc/init.d/apparmor restart


Um Apparmor für MySQL tatsächlich zu deaktivieren, musste ich Folgendes
silver_mx

14

Ich weiß, dass Sie gesagt haben, dass Sie bereits versucht haben, Berechtigungen auf 777 festzulegen, aber da ich den Beweis habe, dass es sich bei mir um ein Berechtigungsproblem handelt, veröffentliche ich das, was ich genau ausgeführt habe, in der Hoffnung, dass es helfen kann. Hier ist meine Erfahrung:

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 Datenbankname --tables test Passwort eingeben: mysqldump: Fehler: 1: Beim Ausführen von 'SELECT INTO' kann keine Datei '/data/dumptest/test.txt' (Fehlercode: 13) erstellt / geschrieben werden OUTFILE 'me @ server: / data $ sudo chmod a + rwx dumptest / me @ server: / data $ mysqldump -u dbuser -p -T dumptest -B Datenbankname --tables test Passwort eingeben: mysqldump: Fehler: 1: (( gleicher Fehler)
Ryan Olson

Oy wusste nicht, dass Kommentare nicht formatiert werden würden, überprüfte jedoch einige verschiedene Methoden. Zuerst mit dem Zielverzeichnis von mysql: mysql, dann mit dem Zielverzeichnis des Benutzers, in dem ich den Befehl dump ausgeführt habe, geben mir beide Methoden immer noch den gleichen Berechtigungsfehler.
Ryan Olson

Für das Protokoll, das für mich gearbeitet trotz der apparmor Berechtigungen geändert hat
Alex

Ich habe versucht, Änderungen an Apparmor vorzunehmen, es hat nicht funktioniert. Das Ändern der Berechtigung 'chmod 777' hat bei mir funktioniert!
Sudarshan_SMD

7

MySQL wird hier dumm. Es wird versucht, Dateien unter / tmp / data / .... zu erstellen. Sie können also Folgendes tun:

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

Dann versuchen Sie Ihre Anfrage. Dies funktionierte für mich nach stundenlangem Debuggen des Problems.


Diese Antwort gefällt mir am besten. Es ist einfach, es funktioniert und es erfordert nicht, dass Sie mit Apparmor fummeln. Die andere Art, Pipes zu verwenden, funktioniert bei großen Exporten aufgrund der gesamten Pufferung nicht gut.
Chris Seline

6

Dieses Problem hat mich schon lange beschäftigt. Mir ist aufgefallen, dass diese Diskussion nicht auf die Lösung für RHEL / Fecora hinweist. Ich verwende RHEL und finde die Konfigurationsdateien für AppArmer unter Ubuntu nicht, aber ich habe mein Problem gelöst, indem ich JEDES Verzeichnis im Verzeichnis PATH für MySQL lesbar und zugänglich gemacht habe. Wenn Sie beispielsweise ein Verzeichnis / tmp erstellen, kann SELECT INTO OUTFILE mit den folgenden beiden Befehlen die Datei .sql AND .sql ausgeben

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

Wenn Sie ein Verzeichnis in Ihrem Home-Verzeichnis / home / tom erstellen, müssen Sie dies sowohl für / home als auch für / home / tom tun.


3
Die Verwendung von / tmp als Beispiel ist keine gute Idee, und Sie möchten den Besitz des Verzeichnisses / tmp (in den meisten Fällen) wirklich nicht ändern.
Sastorsl

Das Ändern des Besitzes von / tmp ist schlecht, aber das Erstellen eines temporären Ordners in / tmp hat chown mysql:mysqlmein Problem gelöst
Samuel Prevost vor

6

Du kannst das :

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

Vielen Dank! Ist es möglich, die Ausgabe als CSV zu steuern?
Hamman Samuel

4

Einige Dinge zu versuchen:

  • ist die secure_file_privSystemvariable gesetzt? Wenn dies der Fall ist, müssen alle Dateien in dieses Verzeichnis geschrieben werden.
  • Stellen Sie sicher, dass die Datei nicht vorhanden ist. MySQL erstellt nur neue Dateien, überschreibt jedoch keine vorhandenen.

1
Ich würde mich auch für secure_file_priv entscheiden. Wenn die Datei bereits vorhanden ist, ist die Fehlermeldung anders (nicht Fehlercode 13).
Xavier Maillard

secure_file_priv ist derzeit nicht festgelegt. Nach meinem Verständnis bedeutet dies, dass ich nicht darauf beschränkt sein sollte, wo ich Dateien schreiben kann. Verstehe ich das falsch und muss ich es explizit auf '/' setzen, wenn ich irgendwo im Dateisystem schreiben möchte?
Ryan Olson

Außerdem überprüfe ich, ob die Datei nicht vorhanden ist, bevor ich die Abfrage ausführe.
Ryan Olson

Danke für die Rückmeldung. Aufgrund Ihrer Erkenntnisse glaube ich nicht, dass einer dieser Vorschläge Ihr Problem verursacht.
Mdma

3

Ich habe das gleiche Problem und habe dieses Problem durch die folgenden Schritte behoben:

  • Betriebssystem: Ubuntu 12.04
  • Lampe installiert
  • Angenommen, Ihr Verzeichnis zum Speichern der Ausgabedatei lautet: / var / www / csv /

Führen Sie den folgenden Befehl auf dem Terminal aus und bearbeiten Sie diese Datei mit dem gedit-Editor, um Ihr Verzeichnis zur Ausgabedatei hinzuzufügen.

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

  • Jetzt wird die Datei im Editor geöffnet. Fügen Sie dort Ihr Verzeichnis hinzu

    / var / www / csv / * rw,

  • Ebenso habe ich in meiner Datei folgendes Bild hinzugefügt:

Geben Sie hier die Bildbeschreibung ein

Führen Sie den nächsten Befehl aus, um die Dienste neu zu starten:

sudo /etc/init.d/apparmor neu starten

Zum Beispiel führe ich die folgende Abfrage im phpmyadmin Query Builder aus, um Daten in einer CSV-Datei auszugeben

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

Es wurde erfolgreich durchgeführt und alle Zeilen mit ausgewählten Spalten in die Datei OUTPUT.csv geschrieben ...


2

In meinem Fall bestand die Lösung darin, jedes Verzeichnis im Verzeichnispfad für mysql( chmod a+rx) lesbar und zugänglich zu machen . Das Verzeichnis wurde weiterhin durch seinen relativen Pfad in der Befehlszeile angegeben.

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

2

Ich bin gerade auf dasselbe Problem gestoßen. Mein Problem war, dass das Verzeichnis, in das ich einen Dump ausführen wollte, keine Schreibberechtigung für den mysqld-Prozess hatte. Der anfängliche SQL-Dump würde ausschreiben, aber das Schreiben der CSV / TXT-Datei würde fehlschlagen. Der SQL-Dump wird anscheinend als aktueller Benutzer ausgeführt, und die Konvertierung in csv / txt wird als Benutzer ausgeführt, der mysqld ausführt. Das Verzeichnis benötigt daher Schreibberechtigungen für beide Benutzer.


1

Sie müssen einen absoluten Pfad angeben, keinen relativen Pfad.

Geben Sie den vollständigen Pfad zum Verzeichnis / data an, in das Sie schreiben möchten.


Das sieht für mich nach einem absoluten Weg aus. Es ist nicht?
Pekka

2
Versuchen Sie dies als MySQL-Benutzer, um zu überprüfen, ob Sie die Datei außerhalb von MySQL erstellen können:touch /data/outfile.csv
Ike Walker

1
Zuerst konnte ich es nicht tun, weil die Shell des MySQL-Benutzers auf / bin / false gesetzt war, sodass ich mich nicht als MySQL anmelden konnte. Um sicherzugehen, dass dies nicht zu dem Problem beiträgt, habe ich die MySQL-Shell auf / bin / bash gesetzt, diesen Benutzer angesprochen und eine Datei in / data berührt. Die Datei wurde erfolgreich erstellt und gehört mysql.
Ryan Olson

3
Sie können ein Konto auch dann anmelden, wenn es eine der "Deaktivierungs" -Shells verwendet: su --shell=/bin/sh nameofaccount
Marc B

Danke, das war mir nicht bewusst.
Ryan Olson

1

Verwendet Ubuntu SELinux? Überprüfen Sie, ob es aktiviert und erzwungen ist. /var/log/audit/audit.log kann hilfreich sein (wenn Ubuntu es dort festhält - das ist der RHEL / Fedora-Speicherort).


0

Ich hatte das gleiche Problem mit einem CentOs 6.7. In meinem Fall wurden alle Berechtigungen festgelegt und der Fehler trat trotzdem auf. Das Problem war, dass sich SE Linux im Modus "Durchsetzen" befand.

Ich habe es mit dem Befehl auf "freizügig" umgestellt sudo setenforce 0

Dann hat alles für mich geklappt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.