Forums

Django - Connect to PA MySQL DB remotely

I know this has been asked a bunch of times here, but none of the suggested solutions seem to work for me. I'm trying to run my Django project from home, and get it to connect to the MySQL db I set up on Python Anywhere, so I set up my database as follows in settings.py:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'samscheding1$scheding_db',
        'USER': 'samscheding1',
        'PASSWORD': 'secret',
        'HOST': 'samscheding1.mysql.pythonanywhere-services.com',
        'PORT': '3306',
    }
}

However, now when I run python3 manage.py runserver my terminal hangs for around a minute (I assume it's trying to connect to the remote db) and then spits out the following exception:

django.db.utils.OperationalError: (2003, "Can't connect to MySQL server on 'samscheding1.mysql.pythonanywhere-services.com' (110)")

I tried running python3 manage.py makemigrations in case it was failing due to a mismatch with the models vs tables, but I get the same behaviour as runserver. I'll include the full stack trace in case it helps:

(env) $ python3 manage.py runserver
Performing system checks...

Unhandled exception in thread started by <function check_errors.<locals>.wrapper at 0x7fd360ff31e0>
Traceback (most recent call last):
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/base/base.py", line 216, in ensure_connection
    self.connect()
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/base/base.py", line 194, in connect
    self.connection = self.get_new_connection(conn_params)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 236, in get_new_connection
    return Database.connect(**conn_params)
  File "/usr/local/lib/python3.6/dist-packages/MySQLdb/__init__.py", line 86, in Connect
    return Connection(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/MySQLdb/connections.py", line 204, in __init__
    super(Connection, self).__init__(*args, **kwargs2)
_mysql_exceptions.OperationalError: (2003, "Can't connect to MySQL server on 'samscheding1.mysql.pythonanywhere-services.com' (110)")

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/dirk/.local/lib/python3.6/site-packages/django/utils/autoreload.py", line 225, in wrapper
    fn(*args, **kwargs)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/core/management/commands/runserver.py", line 120, in inner_run
    self.check(display_num_errors=True)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/core/management/base.py", line 364, in check
    include_deployment_checks=include_deployment_checks,
  File "/home/dirk/.local/lib/python3.6/site-packages/django/core/management/base.py", line 351, in _run_checks
    return checks.run_checks(**kwargs)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/core/checks/registry.py", line 73, in run_checks
    new_errors = check(app_configs=app_configs)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/core/checks/model_checks.py", line 27, in check_all_models
    errors.extend(model.check(**kwargs))
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/models/base.py", line 1200, in check
    errors.extend(cls._check_fields(**kwargs))
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/models/base.py", line 1272, in _check_fields
    errors.extend(field.check(**kwargs))
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 894, in check
    errors = super().check(**kwargs)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 206, in check
    errors.extend(self._check_backend_specific_checks(**kwargs))
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 303, in _check_backend_specific_checks
    return connections[db].validation.check_field(self, **kwargs)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/base/validation.py", line 21, in check_field
    field_type = field.db_type(self.connection)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 648, in db_type
    return connection.data_types[self.get_internal_type()] % data
  File "/home/dirk/.local/lib/python3.6/site-packages/django/utils/functional.py", line 36, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 133, in data_types
    if self.features.supports_microsecond_precision:
  File "/home/dirk/.local/lib/python3.6/site-packages/django/utils/functional.py", line 36, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/mysql/features.py", line 65, in supports_microsecond_precision
    return self.connection.mysql_version >= (5, 6, 4)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/utils/functional.py", line 36, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 345, in mysql_version
    with self.temporary_connection() as cursor:
  File "/usr/lib/python3.6/contextlib.py", line 81, in __enter__
    return next(self.gen)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/base/base.py", line 576, in temporary_connection
    cursor = self.cursor()
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/base/base.py", line 255, in cursor
    return self._cursor()
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/base/base.py", line 232, in _cursor
    self.ensure_connection()
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/base/base.py", line 216, in ensure_connection
    self.connect()
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/base/base.py", line 216, in ensure_connection
    self.connect()
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/base/base.py", line 194, in connect
    self.connection = self.get_new_connection(conn_params)
  File "/home/dirk/.local/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 236, in get_new_connection
    return Database.connect(**conn_params)
  File "/usr/local/lib/python3.6/dist-packages/MySQLdb/__init__.py", line 86, in Connect
    return Connection(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/MySQLdb/connections.py", line 204, in __init__
    super(Connection, self).__init__(*args, **kwargs2)
django.db.utils.OperationalError: (2003, "Can't connect to MySQL server on 'samscheding1.mysql.pythonanywhere-services.com' (110)")

See the help page here. Use the manual method and then tell your local Django to connect to the local host with the local port.

Thanks for the response Glenn, I changed my host to 127.0.0.1 and it works with tunneling. It's a little slow for development though. I'm looking at ways to speed it up now

Hi samscheding1 and glenn, I had a similar issue and was able to solve using this topic. Thank you for this.

Firstly, I'd like to share my experience as well. I think it will be even more clearer for people who have a setup similar to what I have. My setup and usual workflow is as such:

I have a Django project hosted at Python Anywhere. I use home computer as the development environment. I make necessary modifications to the code and when everything is ok I push to my git repo. Then I go to Python Anywhere shell and pull the latest version. Initially I was using sqlite3 backend and there were separate databases for development and production. Due to various reasons, I decided to shift to using MySQL. I have a paid account, so with ease I have chosen Python Anywhere's MySQL server. At that point -it might not be the best practice but nonetheless- I have decided to use the same database for my production and development environments. It seemed a better alternative compared to, say for example, using sqlite in development and MySQL in production, or setting up a separate MySQL server at local. Sqlite to MySQL transfer was successful and new database worked well for production. But, in development I had the problem which in the end lead to me to this topic. Namely, the problem was having django.db.utils.OperationalError: (2003, "Can't connect to MySQL server on 'username.mysql.pythonanywhere-services.com' (60)") error during local python manage.py runserver command.

It is solved now, and I now I do the following during working in development environment (so at home computer):

  • I open a new tab in terminal and start a connection and keep it open during the development process:

ssh -L 3306:username.mysql.pythonanywhere-services.com:3306 username@ssh.pythonanywhere.com

  • I change host = "username.mysql.pythonanywhere-services.com" to host = "127.0.0.1" in setttings.py

@samscheding1 I also observe a slowness issue. Have you managed to find a solution to speed it up?

Thanks.

@cansucullu Unfortunately I wasn't able to make it faster, though I didn't try very hard. I ended up not using this due to the network latency and the fact that it was just a nice feature for me, rather than a necessity.

Alright then. I can survive with this as well, I guess. Thank you!

Thanks for the details! Yes, connecting to a remote database is always going to be slow. There's an initial very slow bit when you start the SSH tunnel, of course, but even after that every query has to traverse the Internet from your local machine to PythonAnywhere, and the results have to come back. This network latency isn't a huge issue when you're running the code on PythonAnywhere (because the servers are closer together, of course) but it will be when you're running it locally, especially if you make lots of small queries (which Django often does).

TBH I'd recommend the SQLite for local development, MySQL for live option. Or alternatively setting up a local MySQL server, though that can be a pain to do.

Hi I am facing some problem in this. The connection is not established. I tried to change the port recommended in another webpage.

ssh -L 3333:username.mysql.pythonanywhere-services.com:3306 username@ssh.pythonanywhere.com <<<<<<:>~ PythonAnywhere SSH. Help @ https://help.pythonanywhere.com/pages/SSHAccess username@ssh.pythonanywhere.com's password: Connection to ssh.pythonanywhere.com closed. Many thanks for any help.

If I run the command with -vv then it gives following messages:

OpenSSH_8.2p1 Ubuntu-4ubuntu0.1, OpenSSL 1.1.1f  31 Mar 2020
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: include /etc/ssh/ssh_config.d/*.conf matched no files
debug1: /etc/ssh/ssh_config line 21: Applying options for *
debug2: resolving "ssh.pythonanywhere.com" port 22
debug2: ssh_connect_direct
debug1: Connecting to ssh.pythonanywhere.com [23.21.200.247] port 22.
debug1: Connection established.
debug1: identity file /home/name/.ssh/id_rsa type -1
debug1: identity file /home/name/.ssh/id_rsa-cert type -1
debug1: identity file /home/name/.ssh/id_dsa type -1
debug1: identity file /home/name/.ssh/id_dsa-cert type -1
debug1: identity file /home/name/.ssh/id_ecdsa type -1
debug1: identity file /home/name/.ssh/id_ecdsa-cert type -1
debug1: identity file /home/name/.ssh/id_ecdsa_sk type -1
debug1: identity file /home/name/.ssh/id_ecdsa_sk-cert type -1
debug1: identity file /home/name/.ssh/id_ed25519 type -1
debug1: identity file /home/name/.ssh/id_ed25519-cert type -1
debug1: identity file /home/name/.ssh/id_ed25519_sk type -1
debug1: identity file /home/name/.ssh/id_ed25519_sk-cert type -1
debug1: identity file /home/faisal/.ssh/id_xmss type -1
debug1: identity file /home/faisal/.ssh/id_xmss-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.1
debug1: Remote protocol version 2.0, remote software version OpenSSH_8.2p1 Ubuntu-4ubuntu0.1
debug1: match: OpenSSH_8.2p1 Ubuntu-4ubuntu0.1 pat OpenSSH* compat 0x04000000
debug2: fd 3 setting O_NONBLOCK
debug1: Authenticating to ssh.pythonanywhere.com:22 as 'username'
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug2: local client KEXINIT proposal
debug2: KEX algorithms: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,ext-info-c
debug2: host key algorithms: rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256,ssh-rsa,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ecdsa-sha2-nistp256@openssh.com,ssh-ed25519,sk-ssh-ed25519@openssh.com
debug2: ciphers ctos: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
debug2: ciphers stoc: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
debug2: MACs ctos: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1
debug2: MACs stoc: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1
debug2: compression ctos: none,zlib@openssh.com,zlib
debug2: compression stoc: none,zlib@openssh.com,zlib
debug2: languages ctos: 
debug2: languages stoc: 
debug2: first_kex_follows 0 
debug2: reserved 0 
debug2: peer server KEXINIT proposal
debug2: KEX algorithms: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256
debug2: host key algorithms: rsa-sha2-512,rsa-sha2-256,ssh-rsa
debug2: ciphers ctos: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
debug2: ciphers stoc: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
debug2: MACs ctos: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1
debug2: MACs stoc: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1
debug2: compression ctos: none,zlib@openssh.com
debug2: compression stoc: none,zlib@openssh.com
debug2: languages ctos: 
debug2: languages stoc: 
debug2: first_kex_follows 0 
debug2: reserved 0 
debug1: kex: algorithm: curve25519-sha256
debug1: kex: host key algorithm: rsa-sha2-512
debug1: kex: server->client cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
debug1: kex: client->server cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ssh-rsa SHA256:zy2jmqxNg/fs6tFZK55OjHTI3B2UofzOiUvTPtcX3/Y
debug1: Host 'ssh.pythonanywhere.com' is known and matches the RSA host key.
debug1: Found key in /home/name/.ssh/known_hosts:1
debug2: set_newkeys: mode 1
debug1: rekey out after 134217728 blocks
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug2: set_newkeys: mode 0
debug1: rekey in after 134217728 blocks
debug1: Will attempt key: /home/name/.ssh/id_rsa 
debug1: Will attempt key: /home/name/.ssh/id_dsa 
debug1: Will attempt key: /home/name/.ssh/id_ecdsa 
debug1: Will attempt key: /home/name/.ssh/id_ecdsa_sk 
debug1: Will attempt key: /home/name/.ssh/id_ed25519 
debug1: Will attempt key: /home/name/.ssh/id_ed25519_sk 
debug1: Will attempt key: /home/name/.ssh/id_xmss 
debug2: pubkey_prepare: done
debug1: SSH2_MSG_EXT_INFO received
debug1: kex_input_ext_info: server-sig-algs=<ssh-ed25519,sk-ssh-ed25519@openssh.com,ssh-rsa,rsa-sha2-256,rsa-sha2-512,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ecdsa-sha2-nistp256@openssh.com>
debug2: service_accept: ssh-userauth
debug1: SSH2_MSG_SERVICE_ACCEPT received
<<<<<<:>~ PythonAnywhere SSH. Help @ https://help.pythonanywhere.com/pages/SSHAccess
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Trying private key: /home/name/.ssh/id_rsa
debug1: Trying private key: /home/name/.ssh/id_dsa
debug1: Trying private key: /home/name/.ssh/id_ecdsa
debug1: Trying private key: /home/name/.ssh/id_ecdsa_sk
debug1: Trying private key: /home/name/.ssh/id_ed25519
debug1: Trying private key: /home/name/.ssh/id_ed25519_sk
debug1: Trying private key: /home/name/.ssh/id_xmss
debug2: we did not send a packet, disable method
debug1: Next authentication method: password
username@ssh.pythonanywhere.com's password: 
debug2: we sent a password packet, wait for reply
debug1: Authentication succeeded (password).
Authenticated to ssh.pythonanywhere.com ([23.21.200.247]:22).
debug1: Local connections to LOCALHOST:3333 forwarded to remote address username.mysql.pythonanywhere-services.com:3306
debug1: Local forwarding listening on ::1 port 3333.
debug2: fd 4 setting O_NONBLOCK
debug1: channel 0: new [port listener]
debug1: Local forwarding listening on 127.0.0.1 port 3333.
debug2: fd 5 setting O_NONBLOCK
debug1: channel 1: new [port listener]
debug1: channel 2: new [client-session]
debug2: channel 2: send open
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
debug1: pledge: network
debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0
debug2: channel_input_open_confirmation: channel 2: callback start
debug2: fd 3 setting TCP_NODELAY
debug2: client_session2_setup: id 2
debug2: channel 2: request pty-req confirm 1
debug1: Sending environment.
debug1: Sending env LANG = en_US.UTF-8
debug2: channel 2: request env confirm 0
debug2: channel 2: request shell confirm 1
debug2: channel_input_open_confirmation: channel 2: callback done
debug2: channel 2: open confirm rwindow 0 rmax 32768
debug2: channel_input_status_confirm: type 99 id 2
debug2: PTY allocation request accepted on channel 2
debug2: channel 2: rcvd adjust 2097152
debug2: channel_input_status_confirm: type 99 id 2
debug2: shell request accepted on channel 2
debug2: channel 2: rcvd eof
debug2: channel 2: output open -> drain
debug2: channel 2: obuf empty
debug2: channel 2: chan_shutdown_write (i0 o1 sock -1 wfd 7 efd 8 [write])
debug2: channel 2: output drain -> closed
debug1: client_input_channel_req: channel 2 rtype exit-status reply 0
debug1: client_input_channel_req: channel 2 rtype eow@openssh.com reply 0
debug2: channel 2: rcvd eow
debug2: channel 2: chan_shutdown_read (i0 o3 sock -1 wfd 6 efd 8 [write])
debug2: channel 2: input open -> closed
debug2: channel 2: rcvd close
debug2: channel 2: almost dead
debug2: channel 2: gc: notify user
debug2: channel 2: gc: user detached
debug2: channel 2: send close
debug2: channel 2: is dead
debug2: channel 2: garbage collecting
debug1: channel 2: free: client-session, nchannels 3
debug1: channel 0: free: port listener, nchannels 2
debug1: channel 1: free: port listener, nchannels 1
Connection to ssh.pythonanywhere.com closed.
Transferred: sent 2344, received 3016 bytes, in 1.3 seconds
Bytes per second: sent 1871.1, received 2407.6
debug1: Exit status 254

Only paid accounts can use SSH to access PythonAnywhere, so SSH tunneling won't work for your account.