关于mysql:如何导出和导入现有用户(具有权限!)

How to Export & Import Existing User (with its Privileges!)

我有一个现有的MySQL实例(测试),包含2个数据库和一些用户,每个用户对每个数据库具有不同的访问权限。

我现在需要复制其中一个数据库(进入生产)和与之关联的用户。

复制数据库很简单:

出口:

1
mysqldump --no-data --tables -u root -p secondb >> secondb_schema.sql

进口:

1
mysql -u root -p -h localhost secondb < secondb_schema.sql

但是,我没有找到从命令行(mysql内部或外部)导出和导入用户的简单方法。

如何从命令行导出和导入用户?

更新:到目前为止,我已经找到了完成此操作的手动(因此容易出错)的步骤:

1
2
-- lists all users
select user,host from mysql.user;

然后找到它的补助金:

1
2
-- find privilege granted to a particular user
show grants for 'root'@'localhost';

然后使用上面"show grants"命令的结果中列出的授权手动创建用户。

我更喜欢更安全,更自动化的方式。 有吗?


我发现导出用户的最简单方法之一是使用Percona的工具pt-show-grants。 Percona工具套件免费,易于安装,易于使用,并提供大量文档。
这是向所有用户或特定用户显示的简单方法。它以SQL格式列出了所有授权和输出。我将举例说明如何显示test_user的所有授权:

1
shell> pt-show-grants --only test_user

该命令的输出示例:

1
2
GRANT USAGE ON *.* TO 'test_user'@'%' IDENTIFIED BY PASSWORD '*06406C868B12689643D7E55E8EB2FE82B4A6F5F4';
GRANT ALTER, INSERT, LOCK TABLES, SELECT, UPDATE ON `test`.* TO 'test_user'@'%';

我通常将输出重新编译成文件,以便我可以编辑我需要的内容,或者将其加载到mysql中。

或者,如果您不想使用Percona工具并且想要转储所有用户,则可以以这种方式使用mysqldump:

1
shell> mysqldump mysql --tables user db > users.sql

注意: - flush特权不适用于此,因为整个数据库未被转储。这意味着您需要手动运行它。

1
shell> mysql -e"FLUSH PRIVILEGES"


1
2
3
4
5
mysql -u<user> -p<password> -h<host> -e"select concat('show grants for ','\'',user,'\'@\'',host,'\'') from mysql.user"> user_list_with_header.txt
sed '1d' user_list_with_header.txt > ./user.txt
while read user; do  mysql -u<user> -p<password> -h<host> -e"$user"> user_grant.txt; sed '1d' user_grant.txt >> user_privileges.txt; echo"flush privileges">> user_privileges.txt; done < user.txt
awk '{print $0";"}'  user_privileges.txt >user_privileges_final.sql
rm user.txt user_list_with_header.txt user_grant.txt user_privileges.txt

上面的脚本将在linux环境中运行,输出将是user_privileges_final.sql,您可以在要复制用户权限的新mysql服务器中导入。

更新:第二个mysql语句的用户缺少-


这些是我现在用作日常备份脚本的一部分(需要root shell和MySQL访问,linux shell,并使用mysql内置架构:

首先,我创建一个包含root密码的文件/var/backup/mysqlroot.cnf,这样我就可以自动化我的脚本,而不是硬编码其中的任何密码:

1
2
[client]
password=(put your password here)

然后我创建一个导出脚本,它转储创建用户命令和这样的授权:

1
2
3
touch /var/backup/backup_sql.sh
chmod 700 /var/backup/backup_sql.sh
vi /var/backup/backup_sql.sh

然后写下面的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash

mysql --defaults-extra-file=/var/backup/mysqlroot.cnf -sNe" \
  SELECT \
    CONCAT( 'CREATE USER \'', User, '\'@\'', Host, '\' IDENTIFIED BY ', authentication_string, '\;' ) AS User \
  FROM mysql.user \
  WHERE \
    User NOT LIKE 'mysql.%' AND CONCAT( User, Host ) <> 'rootlocalhost' AND User <> 'debian-sys-maint' \
"


mysql --defaults-extra-file=/var/backup/mysqlroot.cnf -sNe" \
  SELECT \
    CONCAT( '\'', User, '\'@\'', Host, '\'' ) as User FROM mysql.user \
  WHERE \
    User NOT LIKE 'mysql.%' \
    AND CONCAT( User, Host ) <> 'rootlocalhost' \
    AND User <> 'debian-sys-maint' \
"
| sort | while read u ;
 do echo"-- $u"; mysql --defaults-extra-file=/var/backup/mysqlroot.cnf -sNe"show grants for $u" | sed 's/$/;/'
done

然后我只需要像这样运行它:
/var/backup/backup_sql.sh> /tmp/exportusers.sql


作为@ Sergey-Podushkin的答案的补充,这个shell脚本代码适用于我:

1
mysql -u<user> -p<password> -N mysql -e"select concat("'", user, "'@'", host, "'"), authentication_string from user where not user like 'root'" | while read usr pw ; do mysql -u<user> -p<password> -N -e"SHOW GRANTS FOR $usr" | sed 's/\(\S\)$/\1;/'; done

我有同样的问题。解决方案是在导入备份后,您需要执行"刷新权限"。然后,用户的权限将在原始数据库中处于活动状态。

所以

mysql -u root -p -h localhost secondb < secondb_schema.sql

mysql -u root;
then in mysql:"flush privileges;"


PhpMyAdmin您可以使用phpMyAdmin。

登录并转到您的数据库或用户有权访问的表。

选择权限

所有有权访问的用户都在那里。

选择导出。所有GRANTS的小窗口都准备好复制和粘贴。


另一个bash one-liner for linux使用而不是Percona工具:

1
mysql -u<user> -p<password> -h<host> -N mysql -e"select concat("'", user, "'@'", host, "'"), authentication_string from user where not user like 'mysql.%'" | while read usr pw ; do echo"GRANT USAGE ON *.* TO $usr IDENTIFIED BY PASSWORD '$pw';" ; mysql -u<user> -p<password> -h<host> -N -e"SHOW GRANTS FOR $usr" | grep -v 'GRANT USAGE' | sed 's/\(\S\)$/\1;/' ; done

用于循环用户以获取grant命令的PHP脚本将如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Set up database root credentials
$host = 'localhost';
$user = 'root';
$pass = 'YOUR PASSWORD';
// ---- Do not edit below this ----
// Misc settings
header('Content-type: text/plain; Charset=UTF-8');
// Final import queries goes here
$export = array();
// Connect to database
try {
    $link = new PDO("mysql:host=$host;dbname=mysql", $user, $pass);
} catch (PDOException $e) {
    printf('Connect failed: %s', $e->getMessage());
    die();
}

// Get users from database
$statement = $link->prepare("select `user`, `host`, `password` FROM `user`");
$statement->execute();
while ($row = $statement->fetch())
{
    $user   = $row[0];
    $host   = $row[1];
    $pass   = $row[2];
    $export[] = 'CREATE USER \''. $user .'\'@\''. $host .'\' IDENTIFIED BY \''. $pass .'\'';
    // Fetch any permissions found in database
    $statement2 = $link->prepare('SHOW GRANTS FOR \''. $user .'\'@\''. $host .'\'');
    $statement2->execute();
    if ($row2 = $statement2->fetch())
    {
        $export[] = $row2[0];
    }
}

$link = null;
echo implode(";
"
, $export);

要点:https://gist.github.com/zaiddabaeen/e88a2d10528e31cd6692


我用一个小的C#程序解决了这个问题。这里有代码生成脚本或直接从源到目标应用授权。如果从Windows - > * nix环境移植,您可能必须考虑区分大小写问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
using System;
using MySql.Data.MySqlClient;
using System.Configuration;
using System.IO;
using System.Collections.Generic;

namespace GenerateUsersScript
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> grantsQueries = new List<string>();

            // Get A Show Grants query for each user
            using (MySqlConnection sourceConn = OpenConnection("sourceDatabase"))
            {
                using (MySqlDataReader usersReader = GetUsersReader(sourceConn))
                {
                    while (usersReader.Read())
                    {
                        grantsQueries.Add(String.Format("SHOW GRANTS FOR '{0}'@'{1}'", usersReader[0], usersReader[1]));
                    }
                }

                Console.WriteLine("Exporting Grants For {0} Users", grantsQueries.Count);

                using (StreamWriter writer = File.CreateText(@".\UserPermissions.Sql"))
                {
                    // Then Execute each in turn
                    foreach (string grantsSql in grantsQueries)
                    {
                        WritePermissionsScript(sourceConn, grantsSql, writer);
                    }

                    //using (MySqlConnection destConn = OpenConnection("targetDatabase"))
                    //{
                    //    MySqlCommand command = destConn.CreateCommand();

                    //    foreach (string grantsSql in grantsQueries)
                    //    {
                    //        WritePermissionsDirect(sourceConn, grantsSql, command);
                    //    }
                    //}
                }
            }

            Console.WriteLine("Done - Press A Key to Continue");

            Console.ReadKey();
        }

        private static void WritePermissionsDirect(MySqlConnection sourceConn, string grantsSql, MySqlCommand writeCommand)
        {
            MySqlCommand cmd = new MySqlCommand(grantsSql, sourceConn);

            using (MySqlDataReader grantsReader = cmd.ExecuteReader())
            {
                while (grantsReader.Read())
                {
                    try
                    {
                        writeCommand.CommandText = grantsReader[0].ToString();

                        writeCommand.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(grantsReader[0].ToString());

                        Console.WriteLine(ex.Message);
                    }
                }
            }
        }

        private static void WritePermissionsScript(MySqlConnection conn, string grantsSql, StreamWriter writer)
        {
            MySqlCommand command = new MySqlCommand(grantsSql, conn);

            using (MySqlDataReader grantsReader = command.ExecuteReader())
            {
                while (grantsReader.Read())
                {
                    writer.WriteLine(grantsReader[0] +";");
                }
            }

            writer.WriteLine();
        }

        private static MySqlDataReader GetUsersReader(MySqlConnection conn)
        {
            string queryString = String.Format("SELECT User, Host FROM USER");
            MySqlCommand command = new MySqlCommand(queryString, conn);
            MySqlDataReader reader = command.ExecuteReader();
            return reader;
        }

        private static MySqlConnection OpenConnection(string connName)
        {
            string connectionString = ConfigurationManager.ConnectionStrings[connName].ConnectionString;
            MySqlConnection connection = new MySqlConnection(connectionString);
            connection.Open();
            return connection;

        }
    }
}

使用包含...的app.config

1
2
3
4
    <connectionStrings>
       
       
    </connectionStrings>