Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Using MySQL / MariaDB via SSH in Golang
package main
import (
type ViaSSHDialer struct {
client *ssh.Client
func (self *ViaSSHDialer) Dial(addr string) (net.Conn, error) {
return self.client.Dial("tcp", addr)
func main() {
sshHost := "" // SSH Server Hostname/IP
sshPort := 22 // SSH Port
sshUser := "ssh-user" // SSH Username
sshPass := "ssh-pass" // Empty string for no password
dbUser := "dbuser" // DB username
dbPass := "dbpass" // DB Password
dbHost := "localhost:3306" // DB Hostname/IP
dbName := "database" // Database name
var agentClient agent.Agent
// Establish a connection to the local ssh-agent
if conn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
defer conn.Close()
// Create a new instance of the ssh agent
agentClient = agent.NewClient(conn)
// The client configuration with configuration option to use the ssh-agent
sshConfig := &ssh.ClientConfig{
User: sshUser,
Auth: []ssh.AuthMethod{},
// When the agentClient connection succeeded, add them as AuthMethod
if agentClient != nil {
sshConfig.Auth = append(sshConfig.Auth, ssh.PublicKeysCallback(agentClient.Signers))
// When there's a non empty password add the password AuthMethod
if sshPass != "" {
sshConfig.Auth = append(sshConfig.Auth, ssh.PasswordCallback(func() (string, error) {
return sshPass, nil
// Connect to the SSH Server
if sshcon, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", sshHost, sshPort), sshConfig); err == nil {
defer sshcon.Close()
// Now we register the ViaSSHDialer with the ssh connection as a parameter
mysql.RegisterDial("mysql+tcp", (&ViaSSHDialer{sshcon}).Dial)
// And now we can use our new driver with the regular mysql connection string tunneled through the SSH connection
if db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mysql+tcp(%s)/%s", dbUser, dbPass, dbHost, dbName)); err == nil {
fmt.Printf("Successfully connected to the db\n")
if rows, err := db.Query("SELECT id, name FROM table ORDER BY id"); err == nil {
for rows.Next() {
var id int64
var name string
rows.Scan(&id, &name)
fmt.Printf("ID: %d Name: %s\n", id, name)
} else {
fmt.Printf("Failure: %s", err.Error())
} else {
fmt.Printf("Failed to connect to the db: %s\n", err.Error())
Copy link

A couple of updates:
1- my dbHost had to be localhost, not
2- had to add HostKeyCallback: ssh.InsecureIgnoreHostKey(), to sshConfig

Thanks for the gist!

Copy link

latdev commented Apr 25, 2019

Amazing! Thanks!

Copy link

very very good, buddy.
thanks a lot.


oh! dude, u have been a big help.

Copy link

eva-ave commented Apr 27, 2021

This worked for me for a remote connection(with jlpellicer's updates)! thank you for sharing! :)

Copy link

@ jlpellicer

wonderful comments. Thanks for you all.

Copy link

avdifua commented Jan 26, 2022

This method depricated line 64:

mysql.RegisterDial("mysql+tcp", (&ViaSSHDialer{sshcon}).Dial)

Do you know how to fix this?

Copy link

vinzenz commented Jan 26, 2022


mysql.RegisterDialContext("mysql+tcp", func(_ context.Context, addr string) (net.Conn, error) {
                dialer := &ViaSSHDialer{sshcon})
		return dialer.Dial(addr)

Copy link

avdifua commented Jan 26, 2022

@vinzenz thanks for your answer!

mysql.RegisterDialContext("mysql+tcp", func(_ context.Context, addr string) (net.Conn, error) {
	dialer := &ViaSSHDialer{sshcon}
	return dialer.Dial(addr)

Thanks! Now it's working!

Copy link

geekgogo commented Sep 9, 2022

thanks dude

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment