MySQL:删除数据库时出错(错误号13;错误号17;错误号39)

63

我无法删除一个数据库:

mysql> drop database mydb;
ERROR 1010 (HY000): Error dropping database (can't rmdir './mydb', errno: 39)

在mysql中存在目录db/mydb,但是里面没有表:

# ls -l db/mydb
-rw-rw---- mysql mysql HIS_STAT.MYD
-rw-rw---- mysql mysql HIS_STAT.MYI

我该怎么办?


听起来像是权限问题。你能发布完整的 ls -l 输出吗? - Chris Henry
@Chris Henry:我已经更新了问题,并附上了 # ls -l mydb 的结果。 - Philippe Blayo
8个回答

132

快速修复

如果您想无论如何都要删除数据库(但请先阅读整篇文章:错误是有原因的,了解原因可能很重要!),您可以:

  • 使用命令SHOW VARIABLES WHERE Variable_name LIKE '%datadir%';找到datadir。
  • 停止MySQL服务器(例如,在Linux上使用service mysql stoprcmysqld stop等,或在Windows上通过SERVICES.MSC使用NET STOP <MYSQL服务名称,通常为MYSQL57或类似名称>)。
  • 进入datadir(这是您应该调查的地方;请参见以下说明)。
  • 删除与数据库同名的目录。
  • 重新启动MySQL服务器并连接到它。
  • 执行DROP DATABASE。
  • 就这样!

Errno 13的原因

MySQL在包含mydb文件夹的父目录中没有写入权限。

使用以下命令进行检查:

ls -la /path/to/data/dir/         # see below on how to discover data dir
ls -la /path/to/data/dir/mydb   

在Linux上,如果您混合使用MySQL和AppArmor/SELinux软件包,则也可能会发生这种情况。发生的情况是,AppArmor期望mysqld将其数据存储在/path/to/data/dir中,并允许完全R/W,但是MySQLd来自不同的分发或构建,它实际上将其数据存储在其他地方(例如:/var/lib/mysql5/data/**而不是/var/lib/mysql/**)。因此,您看到的是目录具有正确的权限和所有权,但仍然会出现Errno 13,因为apparmor/selinux不允许访问它。
要进行验证,请检查系统日志以查找安全违规,手动检查apparmor/selinux配置,或模拟mysql用户并尝试进入基本var目录,然后逐步cd直到进入目标目录,并运行类似于touch aardvark && rm aardvark的命令。如果权限和所有权匹配,但以上操作仍然产生访问错误,则很可能是安全框架问题。 "易修复"被认为是有害的 我偶然在一个“专家论坛”上发现了一个“易修复”的建议(不是Stack Overflow,谢天谢地),这也是我有时会找到Web和FTP问题的“解决方法”——chown 777。请永远不要这样做。对于那些还不知道的人来说,777(或775、666)不是MySQL程序员忘记应用不想让你知道的神奇数字。每个数字都有一个含义,777意味着“我同意任何人对我的东西做任何他们想做的事情,包括将其作为二进制或shell脚本执行”。通过这样做(很可能你不能在合理配置的系统上这样做),
  • 你会使一些注重安全的程序拒绝再次运行(例如,如果你对你的SSH密钥这样做,再见SSH连接;等等),因为它们意识到它们现在处于一个不安全的环境中。
  • 你允许几乎所有具有任何访问系统的级别的人读取和写入你的数据,无论MySQL是否允许,MySQL本身不知道——也就是说,整个数据库可能会被悄悄地破坏。
  • 极端困境下,绝望而有知识的人们可能会做到上述事情,以重新获得对无法访问的MySQL安装程序的访问权(即使mysqladmin也不再授予本地访问权限),并且一旦事情恢复正常,这些事情将立即被撤销——这不是一个永久性的变化,即使那时。这也不是“能够删除我的DB的一个奇怪技巧”的修复方法。

(不用说,这几乎从来不是任何Web或FTP问题的真正解决方法。解决“最近,妻子的钥匙无法打开前门,她无法进入我们的家”的方法是“检查钥匙或修理或更换锁”,尽管chown 777显然更快,但它是“只需将前门敞开!易如反掌!最坏的情况是什么?”)

Errno 39的原因

这个代码意味着“目录非空”。该目录包含一些MySQL不知道的隐藏文件。对于非隐藏文件,请参见Errno 17。解决方案是相同的。

Errno 17的原因

这个代码意味着“文件已存在”。该目录包含一些MySQL文件,MySQL不想删除它们。这些文件可能是通过SELECT ... INTO OUTFILE "filename";命令创建的,其中filename没有路径。在这种情况下,MySQL进程会在其当前工作目录中创建它们(在OpenSuSE 12.3上测试的MySQL 5.6中,该目录是数据库的数据目录,例如/var/lib/mysql/data/nameofdatabase)。

可重现性:

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1676
Server version: 5.6.12-log openSUSE package
[ snip ]    

mysql> CREATE DATABASE pippo;
Query OK, 1 row affected (0.00 sec)

mysql> USE pippo;
Database changed
mysql> SELECT version() INTO OUTFILE 'test';
Query OK, 1 row affected (0.00 sec)

mysql> DROP DATABASE pippo;
ERROR 1010 (HY000): Error dropping database (can't rmdir './pippo/', errno: 17)

-- now from another console I delete the "test" file, without closing this connection
-- and just retry. Now it works.

mysql> DROP DATABASE pippo;
Query OK, 0 rows affected (0.00 sec)

Move the file(s) outside (or delete if not needed) and retry. Also, determine why they were created in the first place - it could point to a bug in some application. Or worse: see below...
UPDATE: Error 17 as exploit flag
This happened on a Linux system with Wordpress installed. Unfortunately the customer was under time constraints and I could neither image the disk or do a real forensics round - I reinstalled the whole machine and Wordpress got updated in the process, so I can only say that I'm almost certain they did it through this plugin.
Symptoms: the mysql data directory contained three files with extension PHP. Wait, what?!? -- and inside the files there was a bulk of base64 code which was passed to base64_decode, gzuncompress and [eval()]. Aha. Of course these were only the first attempts, the unsuccessful ones. The site had been well and truly pwn3d.
如果你在mysql数据目录中找到一个导致错误17的文件,使用file工具检查它或使用杀毒软件扫描它。或者直接检查它的内容。不要假设它是因为某些无害的错误而存在。
(不用说,为了视觉检查文件,永远不要双击它)。
在这种情况下,受害者(他有一些朋友“进行维护”)从未想到自己已被黑客攻击,直到维护/更新/任何脚本运行DROP DATABASE并出现错误。从CPU负载和syslog消息来看,我相当确定主机已成为垃圾邮件农场。
另一个错误17。
如果你在两个MySQL安装之间进行rsync或复制,它们的版本相同但平台或文件系统不同(比如Linux或Windows),这是被不鼓励且有风险的,但仍然有许多人这样做。尤其是当大小写敏感性设置不同时,你可能会意外地得到同一文件(数据、索引或元数据)的两个版本,例如Customers.myiCustomer.MYI。MySQL使用其中一个,并且对另一个一无所知(可能已过时且导致灾难性的同步)。当删除数据库时(在许多mysqldump ... | ... mysql备份方案中也会发生),DROP将失败,因为存在额外的文件(或这些额外的文件)。如果出现这种情况,你应该能够通过文件时间或从它们的大小写方案与其他表的大多数不同来识别需要手动删除的过时文件。

查找data-dir

通常情况下,您可以通过检查my.cnf文件(在Linux上为/etc/my.cnf/etc/sysconfig/my.cnf/etc/mysql/my.cnf;在Windows中为MySQL程序文件目录下的my.ini),在[mysqld]标题下找到datadir来查找数据目录。
或者,您也可以向MySQL本身询问:
mysql> SHOW VARIABLES WHERE Variable_name LIKE '%datadir%';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| datadir       | /var/lib/mysql/ |
+---------------+-----------------+
1 row in set (0.00 sec)

感谢 @xk0der 的提醒(但我认为那应该是一个 评论)。已将有关 my.cnf 的建议添加到答案中。errno 13 的问题可能对来这里进行故障排除的人有用,所以我决定保留它。 - LSerni
2
在我的情况下,我尝试使用OUTFILE来获取表的转储,并将该文件保存在数据库名称下的数据目录中。通过删除该文件解决了这个问题。 - Taranjeet
1
我曾经在一个命令正在转储数据库内容时关闭服务器,导致了errno 39的错误。这导致在该数据库目录中留下了一些垃圾数据csv文件,需要手动删除。 - jschultz410

34
在我的情况下,是由于“lower_case_table_names”参数引起的。
当启用lower_case_table_names参数并尝试删除包含大写表名的数据库时,会引发错误编号39。
通过将小写参数更改回先前的状态来解决此问题。

可能是由于该设置,返回 True 值。但是,我认为恢复该设置并不是正确的解决方案,而是一种妥协。 - Vikas B
5
解决了我的问题。你可以撤销它,删除你的数据库再将其恢复回来... - c4k
是的,这也是我的原因。 - Ashish Ratan

13

只需前往 /opt/lampp/var/mysql

在那里,您可以找到您的数据库名称。打开那个文件夹。如果有任何文件,请将其删除

现在转到 phpmyadmin 并删除那个数据库


5

关于错误代码39,您可以直接在磁盘上删除物理表文件。其位置取决于您的操作系统分发和设置。在Debian中,通常位于/var/lib/mysql/数据库名/下。因此,请执行以下操作:

rm -f /var/lib/mysql/<database_name>/

然后使用您选择的工具或使用命令从数据库中删除:

DROP DATABASE <database_name>

1
这对我有用。在删除文件之前,首先停止mysql服务器(service mysql stop),然后删除文件并重新启动。最后登录mysql并DROP db。 - bakalov
非常感谢,非常有用,帮我省了不少事,简单直接。 - Ariane Martins Gomes Do Rego

1

我使用XAMP服务器来管理MySQL,但是当我想删除数据库时,遇到了以下问题:

#1010 - Error dropping database (can't rmdir '.\database_name', errno: 41 "Directory not empty")

我想使用SQL查询删除数据,但是出现了上述错误。
我打开XAMP安装文件夹“xamp\mysql\data”,里面有像database_name1、database_name2等数据库模式文件夹。
只需删除与database_name相同的文件夹,然后重新打开MySQL,数据库/模式就可以成功删除了。

0
这是我解决它的方法:
mysql> DROP DATABASE mydatabase;
ERROR 1010 (HY000): Error dropping database (can't rmdir '.\mydatabase', errno: 13)
mysql> 

我去删除这个目录:C:\...\UniServerZ\core\mysql\data\mydatabase

mysql> DROP DATABASE mydatabase;
ERROR 1008 (HY000): Can't drop database 'mydatabase'; database doesn't exist

-1
在我的情况下,一个不属于数据库的附加文件被放置在了数据库文件夹中。在删除所有表后,Mysql发现文件夹不为空,从而触发了错误。我移除了该文件,然后删除数据库就正常工作了。

-2

在Linux中,只需转到“/var/lib/mysql”,右键单击并(以管理员身份打开),在mysql文件夹内找到与您的数据库名称对应的文件夹并将其删除。 就这样。 数据库已删除。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接