¿Cómo puedo exportar los privilegios de MySQL y luego importarlos a un nuevo servidor?

88

Sé cómo exportar / importar las bases de datos usando mysqldump y está bien, pero ¿cómo obtengo los privilegios en el nuevo servidor?

Para obtener puntos adicionales, ya hay un par de bases de datos existentes en la nueva, ¿cómo importo los privilegios de los servidores antiguos sin eliminar la pareja de los existentes?

Servidor antiguo: 5.0.67-comunidad

Nuevo servidor: 5.0.51a-24 + lenny1

EDITAR: Tengo un volcado de la base de datos 'mysql' del servidor antiguo y ahora quiero saber la forma correcta de fusionarme con la base de datos 'mysql' en el servidor nuevo.

Intenté una 'Importación' directa usando phpMyAdmin y terminé con un error con respecto a un duplicado (uno que ya he migrado manualmente).

¿Alguien tiene una forma elegante de fusionar las dos bases de datos 'mysql'?

Gareth
fuente
1. ¿Es un requisito para usted usar PHPMyAdmin? Si es así, escribiré algunas instrucciones específicas de PHPMyAdmin para usted. 2. Desde PHPMyAdmin si intenta "seleccionar * desde mysql.user limit 1;" ¿obtienes resultados o un error?
Bruno Bronosky
1
Como mencioné a continuación, creo que el script mygrants de Richard es una buena manera de obtener información de subvenciones. Sin embargo, también puede intentar editar el archivo de volcado para comentar INSERT a la tabla de usuario para los usuarios que ya existen. Luego se copiarán los privilegios para los dbs restaurados desde el servidor anterior. Si ya ha asignado privilegios manualmente para algunos de los dbs que restauró en el nuevo cuadro, busque estos nombres de tabla en los archivos de privilegios y también coméntelos. No olvides un flush_privileges después. Buena descripción de la base de datos mysql en: grahamwideman.com/gw/tech/mysql/perms/index.htm
nedm

Respuestas:

169

No te metas con el mysql db. Allí hay mucho más que solo la tabla de usuarios. Su mejor apuesta es el comando " MOSTRAR SUBVENCIONES PARA". Tengo muchos alias y funciones de mantenimiento de CLI en mi .bashrc (en realidad, mis .bash_aliases que obtengo en mi .bashrc). Esta función:

mygrants()
{
  mysql -B -N $@ -e "SELECT DISTINCT CONCAT(
    'SHOW GRANTS FOR \'', user, '\'@\'', host, '\';'
    ) AS query FROM mysql.user" | \
  mysql $@ | \
  sed 's/\(GRANT .*\)/\1;/;s/^\(Grants for .*\)/## \1 ##/;/##/{x;p;x;}'
}

El primer comando mysql usa SQL para generar SQL válido que se canaliza al segundo comando mysql. La salida se canaliza a través de sed para agregar bonitos comentarios.

El $ @ en el comando le permitirá llamarlo como: mygrants --host = prod-db1 --user = admin --password = secret

Puede usar su kit completo de herramientas de Unix en esto de la siguiente manera:

mygrants --host=prod-db1 --user=admin --password=secret | grep rails_admin | mysql --host=staging-db1 --user=admin --password=secret

Esa es LA forma correcta de mover a los usuarios. Su ACL MySQL se modifica con SQL puro.

Bruno Bronosky
fuente
Esta es realmente una buena función de ayuda bash que funciona muy bien. Tome la salida de eso y pueda ejecutarse en el nuevo servidor y los privilegios se ingresarían de manera adecuada y precisa.
Jeremy Bouse
1
Me encanta tu función, hoy me ahorró mucho trabajo. Gracias, gracias, gracias ...
Fabio
2
Esto es genial, pero tiene un gran defecto. Se agrega un "\" adicional a los guiones bajos en los nombres de las bases de datos, por lo que si tiene, por ejemplo, un usuario con privilegios específicos en una base de datos llamada foo_bar, se representará como foo \ _bar en lugar de foo_bar, de modo que no se importará correctamente . Al menos, esto sucede si guarda el resultado de su script en un archivo SQL y luego lo importa al nuevo servidor. No he probado la tubería directa de exportación e importación en una sola línea.
matteo
1
Ten cuidado con este comando. Si tiene en la usertabla un usuario con host %, pero luego en la dbtabla tiene entradas donde hostes un valor explícito, esas entradas en la dbtabla no se recuperan utilizando este método.
Mitar
1
@matteo Agregue -ral segundo comando mysql en la función y no se generarán los escapes dobles mysql. por ejemplo:mysql -r $@
LIFO
45

Hay dos métodos para extraer subvenciones SQL de una instancia de MySQL

MÉTODO 1

Puede usar pt-show- grant de Percona Toolkit

MYSQL_CONN="-uroot -ppassword"
pt-show-grants ${MYSQL_CONN} > MySQLUserGrants.sql

MÉTODO # 2

Puedes emular pt-show-grantscon lo siguiente

MYSQL_CONN="-uroot -ppassword"
mysql ${MYSQL_CONN} --skip-column-names -A -e"SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host,''';') FROM mysql.user WHERE user<>''" | mysql ${MYSQL_CONN} --skip-column-names -A | sed 's/$/;/g' > MySQLUserGrants.sql

Cualquiera de los métodos producirá un volcado de SQL puro de las concesiones de MySQL. Todo lo que queda por hacer es ejecutar el script en un nuevo servidor:

mysql -uroot -p -A < MySQLUserGrants.sql

Darle una oportunidad !!!

RolandoMySQLDBA
fuente
1
pt-show-grant es exactamente lo que quieres para esto, funciona muy bien.
Glenn Plas
Percona es pura maravilla.
sjas
77
¡Pero la respuesta # 2 es igual de buena y funcionará sin software adicional!
sjas
14

La respuesta de Richard Bronosky fue extremadamente útil para mí. ¡¡¡Muchas gracias!!!

Aquí hay una pequeña variación que me fue útil. Es útil para transferir usuarios, por ejemplo, entre dos instalaciones de Ubuntu que ejecutan phpmyadmin. Simplemente descargue los privilegios para todos los usuarios, aparte de root, phpmyadmin y debian-sys-maint. El código es entonces

mygrants()
{
mysql -B -N $@ -e "SELECT DISTINCT CONCAT(
'SHOW GRANTS FOR ''', user, '''@''', host, ''';'
) AS query FROM mysql.user WHERE user NOT IN ('root','phpmyadmin','debian-sys-maint')"  | \
mysql $@ | \
sed 's/\(GRANT .*\)/\1;/;s/^\(Grants for .*\)/## \1 ##/;/##/{x;p;x;}'
}
rmldj
fuente
2
Si miras mi ejemplo donde grep rails_adminpuedo inferir cómo hacer esto sin hacer una función especial para cada caso límite. Utilice la opción de "inversión" de grep de la siguiente manera:mygrants --host=prod-db1 --user=admin --password=secret | grep -Ev 'root|phpmyadmin|debian-sys-maint' | mysql --host=staging-db1 --user=admin --password=secret
Bruno Bronosky,
7

O utilice percona-toolkit (anteriormente maatkit) y use pt-show-grants(o mk-show-grants) para ese propósito. No hay necesidad de scripts engorrosos y / o procedimientos almacenados.

MrkiMile
fuente
5

Puede mysqldump la base de datos 'mysql' e importar a la nueva; se requerirá un flush_privileges o un reinicio y definitivamente querrá hacer una copia de seguridad del mysq db existente primero.

Para evitar eliminar sus privilegios existentes, asegúrese de agregar en lugar de reemplazar filas en las tablas de privilegios (db, columnas_priv, host, func, etc.).

nedm
fuente
Gracias @nedm Parece que el molesto servidor cPanel del que estoy tratando de quitar el dbs no muestra el db 'mysql'. De lo contrario, probaría y afirmaría su respuesta. Una vez que lo resuelva, lo comprobaré. Gracias.
Gareth
Eso es desafortunado pero comprensible, es probable que no pueda acceder a ninguna base de datos que no sea la propiedad directa de su usuario en una base de datos compartida.
Dave Cheney
Ay, sí, sin acceso a 'mysql' será difícil hacer algo relacionado con los usuarios o los permisos. ¿Tiene acceso a la línea de comando? ¿Se puede ejecutar mysqldump desde el terminal o la línea de comando (NO desde el shell mysql)? mysqldump -u username -ppassword mysql> mysqldump.sql
nedm
Se podía acceder al db 'mysql' desde Cpanel WHM si me conectaba como 'root'. Desde allí puedo acceder a una versión de phpmyadmin que tiene la base de datos 'mysql' que contiene permisos
Gareth
Al fusionarse con un esquema mysql existente, es casi seguro que los datos extraídos de un esquema mysql a través de mysqldump sean problemáticos. Está manipulando un esquema complejo con relaciones forzadas, etc. Este esquema es tan complejo, de hecho, que crearon una sintaxis SQL dedicada (GRANT, REVOKE, DROP USER, etc.) para tratar con él. Su extracto, sin embargo, consiste solo en declaraciones INSERT. Me estoy quedando sin personajes aquí. ¿Necesito continuar?
Bruno Bronosky
4

También puede hacerlo como un procedimiento almacenado:

CREATE PROCEDURE spShowGrants()
    READS SQL DATA
    COMMENT 'Show GRANT statements for users'
BEGIN
    DECLARE v VARCHAR(64) CHARACTER SET utf8;
    DECLARE c CURSOR FOR
    SELECT DISTINCT CONCAT(
        'SHOW GRANTS FOR ', user, '@', host, ';'
    ) AS query FROM mysql.user;
    DECLARE EXIT HANDLER FOR NOT FOUND BEGIN END;  
    OPEN c;
    WHILE TRUE DO
        FETCH c INTO v;
        SET @v = v;
        PREPARE stmt FROM @v;
        EXECUTE stmt;
    END WHILE;
    CLOSE c;
END

y llámalo con

$ mysql -p -e "CALL spShowGrants" mysql

luego canalice la salida a través del comando Richards sed para obtener una copia de seguridad de los privilegios.

Lenny
fuente
3

Si bien parece que la respuesta de @Richard Bronosky es la correcta, me encontré con esta pregunta después de intentar migrar un conjunto de bases de datos de un servidor a otro y la solución fue mucho más simple:

server1$ mysqldump -u root -p --all-databases > dbdump.sql

server2$ mysql -u root -p < dbdump.sql

En este punto, todos mis datos eran visibles si iniciaba sesión como root, la mysql.usertabla tenía todo lo que esperaba, pero no podía iniciar sesión como ninguno de los otros usuarios y encontré esta pregunta asumiendo que tendría que volver emitir las GRANTdeclaraciones.

Sin embargo, resulta que el servidor mysql simplemente necesitaba reiniciarse para que los privilegios actualizados en las mysql.*tablas tuvieran efecto:

server2$ sudo restart mysql

¡Ojalá eso ayude a alguien más a lograr lo que debería ser una tarea simple!

Tom
fuente
Ah, y mi situación era ligeramente diferente a la de los OP, ya que no estaba tratando de fusionar un volcado en un servidor con bases de datos / usuarios existentes.
Tom
2
En realidad, no tiene que reiniciar MySQLd para 'actualizar los privilegios'. Se puede hacer con el comando MySQL 'privilegios de descarga;'
CloudWeavers
El problema con este enfoque es que solo funciona cuando las versiones de origen y destino de MySQL son iguales. De lo contrario, es posible que tenga problemas porque la tabla mysql.user de origen tiene columnas diferentes a la tabla mysql.user de destino, por ejemplo.
Mitar
3

¿Qué tal un script PHP? :)

Vea la fuente en este script y tendrá todos los privilegios enumerados:

//connect
mysql_select_db("mysql", mysql_connect("localhost","root",""));

//create grants select statements
$rs = mysql_query("SELECT DISTINCT CONCAT('SHOW GRANTS FOR ''', user, '''@''', host, ''';') AS query FROM user");

//iterate through grants
while ($row=mysql_fetch_array($rs)) {
    //run grant query
    $rs2 = mysql_query($row['query']);
    //iterate through results
    while($row2 = mysql_fetch_array($rs2)){
        //print results
        echo $row2[0] . ";\n\n";
    }
}
Ibrahim Lawal
fuente
2

cree un archivo de script de shell con el siguiente código:

###############################################
echo "SELECT DISTINCT CONCAT (\"show grants for '\", user, \"'@'\", host, \"';\") AS query FROM mysql.user; " >   script.sql    
echo "*** You will be asked to enter the root password twice ******"    
mysql -u root -p  < script.sql > output.sql ;    
cat output.sql | grep show > output1.sql  ; rm output.sql -f ; 
mysql -u root -p  < output1.sql > output.sql ;
clear
echo "-----Exported Grants-----"    
cat  output.sql ; rm  output.sql   output1.sql -f    
echo "-------------------------"
rm  script.sql -f
# #

**** luego ejecútelo en el shell de esta manera: se le pedirá que ingrese la contraseña de root dos veces y luego se mostrará GRANTS SQL en la pantalla. ****


fuente
0

One-liner haciendo más o menos lo mismo que lo increíble pt-show-grants:

mysql --skip-column-names -A -e"SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host,''';') FROM mysql.user WHERE user<>''" | mysql --skip-column-names -A | sed 's/$/;/g'

Basado solo en herramientas Unix, no se necesita software adicional.

Ejecutar desde un shell bash, se supone que tiene un trabajo .my.cnfdonde mysql rootse puede leer la contraseña de su usuario.

sjas
fuente
Dupliqué la mitad de la publicación de @rolandomysqldba después de regresar medio año después, me acabo de dar cuenta.
sjas