LMS/CMS can't connect to MYSQL database (Tutor 20.0.1)

I want to simply launch an openedx platform via tutor (version 20.0.1) … but the LMS/CMS can’t connect to MYSQL database

I have freshly installed tutor (20.0.1) on a new server (all detailed steps for easy reproduction of this problem are described at the bottom). After running tutor local launch the mysql container seems to run correctly (container is up and the logs dont show any error only some warnings (attached at bottom). But the LMS and CMS containers are failing. The reason for this can be found in the logs (complete logs are attached at bottom):

**MYSQL Connectivity error: **
MySQLdb.OperationalError: (2003, “Can’t connect to MySQL server on ‘mysql:3306’ (111)”)

and

User authentication error:
MySQLdb.OperationalError: (1045, “Access denied for user ‘openedx’@‘172.18.0.10’ (using password: YES)”)

According to the documentation the password for mysql database is generated automatically.

Using

Tutor version: 20.0.1
OS: Ubuntu-24.0.4

Logs

MYSQL logs

(.venv) openedx@ubuntu:~$ tutor local logs mysql

docker compose -f /home/openedx/.local/share/tutor/env/local/docker-compose.yml -f /home/openedx/.local/share/tutor/env/local/docker-compose.prod.yml --project-name tutor_local logs mysql

mysql-1 | 2025-10-04 09:59:33+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.4.0-1.el9 started.

mysql-1 | 2025-10-04 09:59:34+00:00 [Note] [Entrypoint]: Initializing database files

mysql-1 | 2025-10-04T09:59:34.433961Z 0 [System] [MY-015017] [Server] MySQL Server Initialization - start.

mysql-1 | 2025-10-04T09:59:34.439794Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.4.0) initializing of server in progress as process 42

mysql-1 | 2025-10-04T09:59:34.473398Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.

mysql-1 | 2025-10-04T09:59:36.166158Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.

mysql-1 | 2025-10-04T09:59:39.575521Z 0 [Warning] [MY-010161] [Server] You need to use --log-bin to make --binlog-expire-logs-seconds work.

mysql-1 | 2025-10-04T09:59:42.468088Z 6 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.

mysql-1 | 2025-10-04T09:59:48.804253Z 0 [System] [MY-015018] [Server] MySQL Server Initialization - end.

mysql-1 | 2025-10-04 09:59:48+00:00 [Note] [Entrypoint]: Database files initialized

mysql-1 | 2025-10-04 09:59:48+00:00 [Note] [Entrypoint]: Starting temporary server

mysql-1 | 2025-10-04T09:59:48.980815Z 0 [System] [MY-015015] [Server] MySQL Server - start.

mysql-1 | 2025-10-04T09:59:49.758851Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.4.0) starting as process 81

mysql-1 | 2025-10-04T09:59:49.873838Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.

mysql-1 | 2025-10-04T09:59:50.999030Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.

mysql-1 | 2025-10-04T09:59:52.259281Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.

mysql-1 | 2025-10-04T09:59:52.259374Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.

mysql-1 | 2025-10-04T09:59:52.294396Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location ‘/var/run/mysqld’ in the path is accessible to all OS users. Consider choosing a different directory.

mysql-1 | 2025-10-04T09:59:52.430784Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: ‘8.4.0’ socket: ‘/var/run/mysqld/mysqld.sock’ port: 0 MySQL Community Server - GPL.

mysql-1 | 2025-10-04T09:59:52.484144Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: /var/run/mysqld/mysqlx.sock

mysql-1 | 2025-10-04 09:59:52+00:00 [Note] [Entrypoint]: Temporary server started.

mysql-1 | ‘/var/lib/mysql/mysql.sock’ → ‘/var/run/mysqld/mysqld.sock’

mysql-1 | Warning: Unable to load ‘/usr/share/zoneinfo/iso3166.tab’ as time zone. Skipping it.

mysql-1 | Warning: Unable to load ‘/usr/share/zoneinfo/leap-seconds.list’ as time zone. Skipping it.

mysql-1 | Warning: Unable to load ‘/usr/share/zoneinfo/leapseconds’ as time zone. Skipping it.

mysql-1 | Warning: Unable to load ‘/usr/share/zoneinfo/tzdata.zi’ as time zone. Skipping it.

mysql-1 | Warning: Unable to load ‘/usr/share/zoneinfo/zone.tab’ as time zone. Skipping it.

mysql-1 | Warning: Unable to load ‘/usr/share/zoneinfo/zone1970.tab’ as time zone. Skipping it.

mysql-1 |

mysql-1 | 2025-10-04 10:00:08+00:00 [Note] [Entrypoint]: Stopping temporary server

mysql-1 | 2025-10-04T10:00:09.103421Z 11 [System] [MY-013172] [Server] Received SHUTDOWN from user root. Shutting down mysqld (Version: 8.4.0).

mysql-1 | 2025-10-04T10:00:10.558480Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.4.0) MySQL Community Server - GPL.

mysql-1 | 2025-10-04T10:00:10.562573Z 0 [System] [MY-015016] [Server] MySQL Server - end.

mysql-1 | 2025-10-04 10:00:11+00:00 [Note] [Entrypoint]: Temporary server stopped

mysql-1 |

mysql-1 | 2025-10-04 10:00:11+00:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.

mysql-1 |

mysql-1 | 2025-10-04T10:00:11.260351Z 0 [System] [MY-015015] [Server] MySQL Server - start.

mysql-1 | 2025-10-04T10:00:12.070764Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.4.0) starting as process 1

mysql-1 | 2025-10-04T10:00:12.150849Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.

mysql-1 | 2025-10-04T10:00:14.153154Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.

mysql-1 | 2025-10-04T10:00:15.619607Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.

mysql-1 | 2025-10-04T10:00:15.623896Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.

mysql-1 | 2025-10-04T10:00:15.655598Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location ‘/var/run/mysqld’ in the path is accessible to all OS users. Consider choosing a different directory.

mysql-1 | 2025-10-04T10:00:15.799821Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: ‘8.4.0’ socket: ‘/var/run/mysqld/mysqld.sock’ port: 3306 MySQL Community Server - GPL.

mysql-1 | 2025-10-04T10:00:16.075368Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: ‘::’ port: 33060, socket: /var/run/mysqld/mysqlx.sock

mysql-1 | 2025-10-04T10:00:25.438974Z 9 [Warning] [MY-013360] [Server] Plugin sha256_password reported: ‘‘sha256_password’ is deprecated and will be removed in a future release. Please use caching_sha2_password instead’

LMS related logs

(.venv) openedx@ubuntu:~$ tutor local logs lms

docker compose -f /home/openedx/.local/share/tutor/env/local/docker-compose.yml -f /home/openedx/.local/share/tutor/env/local/docker-compose.prod.yml --project-name tutor_local logs lms

lms-1 | [uWSGI] getting INI configuration from /openedx/uwsgi.ini

lms-1 | [uwsgi-static] added mapping for /static => /openedx/staticfiles/

lms-1 | [uwsgi-static] added mapping for /media => /openedx/media/

lms-1 | *** Starting uWSGI 2.0.24 (64bit) on [Sat Oct 4 09:59:34 2025] ***

lms-1 | compiled with version: 11.4.0 on 23 September 2025 06:51:40

lms-1 | os: Linux-6.8.0-71-generic #71-Ubuntu SMP PREEMPT_DYNAMIC Tue Jul 22 16:52:38 UTC 2025

lms-1 | nodename: e478f2056851

lms-1 | machine: x86_64

lms-1 | clock source: unix

lms-1 | detected number of CPU cores: 2

lms-1 | current working directory: /openedx/edx-platform

lms-1 | detected binary path: /openedx/venv/bin/uwsgi

lms-1 | !!! no internal routing support, rebuild with pcre support !!!

lms-1 | your memory page size is 4096 bytes

lms-1 | detected max file descriptor number: 1048576

lms-1 | building mime-types dictionary from file /etc/mime.types…1516 entry found

lms-1 | lock engine: pthread robust mutexes

lms-1 | thunder lock: enabled

lms-1 | uWSGI http bound on 0.0.0.0:8000 fd 4

lms-1 | uwsgi socket 0 bound to TCP address 127.0.0.1:46229 (port auto-assigned) fd 3

lms-1 | Python version: 3.11.8 (main, Sep 2 2025, 08:09:41) [GCC 11.4.0]

lms-1 | Python main interpreter initialized at 0x7ae09d160278

lms-1 | python threads support enabled

lms-1 | your server socket listen backlog is limited to 100 connections

lms-1 | your mercy for graceful operations on workers is 60 seconds

lms-1 | mapped 231048 bytes (225 KB) for 2 cores

lms-1 | *** Operational MODE: preforking ***

lms-1 | Traceback (most recent call last):

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 289, in ensure_connection

lms-1 | self.connect()

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 270, in connect

lms-1 | self.connection = self.get_new_connection(conn_params)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/mysql/base.py”, line 247, in get_new_connection

lms-1 | connection = Database.connect(**conn_params)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/MySQLdb/_init_.py”, line 121, in Connect

lms-1 | return Connection(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/MySQLdb/connections.py”, line 200, in _init_

lms-1 | super()._init_(*args, **kwargs2)

lms-1 | MySQLdb.OperationalError: (2003, “Can’t connect to MySQL server on ‘mysql:3306’ (111)”)

lms-1 |

lms-1 | The above exception was the direct cause of the following exception:

lms-1 |

lms-1 | Traceback (most recent call last):

lms-1 | File “lms/wsgi.py”, line 21, in

lms-1 | application = get_wsgi_application()

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/core/wsgi.py”, line 13, in get_wsgi_application

lms-1 | return WSGIHandler()

lms-1 | ^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/core/handlers/wsgi.py”, line 118, in _init_

lms-1 | self.load_middleware()

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/core/handlers/base.py”, line 61, in load_middleware

lms-1 | mw_instance = middleware(adapted_handler)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/edx_django_utils/monitoring/internal/middleware.py”, line 518, in _init_

lms-1 | if not self._is_enabled():

lms-1 | ^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/edx_django_utils/monitoring/internal/middleware.py”, line 586, in _is_enabled

lms-1 | return waffle.switch_is_active(‘edx_django_utils.monitoring.enable_frontend_monitoring_middleware’)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/waffle/_init_.py”, line 23, in switch_is_active

lms-1 | switch = get_waffle_switch_model().get(switch_name)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/waffle/models.py”, line 59, in get

lms-1 | obj = cls.get_from_db(name)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/waffle/models.py”, line 72, in get_from_db

lms-1 | return objects.get(name=name)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/models/manager.py”, line 87, in manager_method

lms-1 | return getattr(self.get_queryset(), name)(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/models/query.py”, line 633, in get

lms-1 | num = len(clone)

lms-1 | ^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/models/query.py”, line 380, in _len_

lms-1 | self._fetch_all()

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/models/query.py”, line 1881, in _fetch_all

lms-1 | self._result_cache = list(self._iterable_class(self))

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/models/query.py”, line 91, in _iter_

lms-1 | results = compiler.execute_sql(

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/models/sql/compiler.py”, line 1560, in execute_sql

lms-1 | cursor = self.connection.cursor()

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 330, in cursor

lms-1 | return self._cursor()

lms-1 | ^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 306, in _cursor

lms-1 | self.ensure_connection()

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 288, in ensure_connection

lms-1 | with self.wrap_database_errors:

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/utils.py”, line 91, in _exit_

lms-1 | raise dj_exc_value.with_traceback(traceback) from exc_value

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 289, in ensure_connection

lms-1 | self.connect()

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 270, in connect

lms-1 | self.connection = self.get_new_connection(conn_params)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/mysql/base.py”, line 247, in get_new_connection

lms-1 | connection = Database.connect(**conn_params)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/MySQLdb/_init_.py”, line 121, in Connect

lms-1 | return Connection(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/MySQLdb/connections.py”, line 200, in _init_

lms-1 | super()._init_(*args, **kwargs2)

lms-1 | django.db.utils.OperationalError: (2003, “Can’t connect to MySQL server on ‘mysql:3306’ (111)”)

lms-1 | unable to load app 0 (mountpoint=‘’) (callable not found or import error)

lms-1 | *** no app loaded. GAME OVER ***

lms-1 | [uWSGI] getting INI configuration from /openedx/uwsgi.ini

lms-1 | [uwsgi-static] added mapping for /static => /openedx/staticfiles/

lms-1 | [uwsgi-static] added mapping for /media => /openedx/media/

lms-1 | *** Starting uWSGI 2.0.24 (64bit) on [Sat Oct 4 10:00:05 2025] ***

lms-1 | compiled with version: 11.4.0 on 23 September 2025 06:51:40

lms-1 | os: Linux-6.8.0-71-generic #71-Ubuntu SMP PREEMPT_DYNAMIC Tue Jul 22 16:52:38 UTC 2025

lms-1 | nodename: e478f2056851

lms-1 | machine: x86_64

lms-1 | clock source: unix

lms-1 | detected number of CPU cores: 2

lms-1 | current working directory: /openedx/edx-platform

lms-1 | detected binary path: /openedx/venv/bin/uwsgi

lms-1 | !!! no internal routing support, rebuild with pcre support !!!

lms-1 | your memory page size is 4096 bytes

lms-1 | detected max file descriptor number: 1048576

lms-1 | building mime-types dictionary from file /etc/mime.types…1516 entry found

lms-1 | lock engine: pthread robust mutexes

lms-1 | thunder lock: enabled

lms-1 | uWSGI http bound on 0.0.0.0:8000 fd 4

lms-1 | uwsgi socket 0 bound to TCP address 127.0.0.1:39875 (port auto-assigned) fd 3

lms-1 | Python version: 3.11.8 (main, Sep 2 2025, 08:09:41) [GCC 11.4.0]

lms-1 | Python main interpreter initialized at 0x7f174f1a3278

lms-1 | python threads support enabled

lms-1 | your server socket listen backlog is limited to 100 connections

lms-1 | your mercy for graceful operations on workers is 60 seconds

lms-1 | mapped 231048 bytes (225 KB) for 2 cores

lms-1 | *** Operational MODE: preforking ***

lms-1 | Traceback (most recent call last):

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 289, in ensure_connection

lms-1 | self.connect()

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 270, in connect

lms-1 | self.connection = self.get_new_connection(conn_params)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/mysql/base.py”, line 247, in get_new_connection

lms-1 | connection = Database.connect(**conn_params)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/MySQLdb/_init_.py”, line 121, in Connect

lms-1 | return Connection(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/MySQLdb/connections.py”, line 200, in _init_

lms-1 | super()._init_(*args, **kwargs2)

lms-1 | MySQLdb.OperationalError: (1045, “Access denied for user ‘openedx’@‘172.18.0.8’ (using password: YES)”)

lms-1 |

lms-1 | The above exception was the direct cause of the following exception:

lms-1 |

lms-1 | Traceback (most recent call last):

lms-1 | File “lms/wsgi.py”, line 21, in

lms-1 | application = get_wsgi_application()

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/core/wsgi.py”, line 13, in get_wsgi_application

lms-1 | return WSGIHandler()

lms-1 | ^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/core/handlers/wsgi.py”, line 118, in _init_

lms-1 | self.load_middleware()

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/core/handlers/base.py”, line 61, in load_middleware

lms-1 | mw_instance = middleware(adapted_handler)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/edx_django_utils/monitoring/internal/middleware.py”, line 518, in _init_

lms-1 | if not self._is_enabled():

lms-1 | ^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/edx_django_utils/monitoring/internal/middleware.py”, line 586, in _is_enabled

lms-1 | return waffle.switch_is_active(‘edx_django_utils.monitoring.enable_frontend_monitoring_middleware’)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/waffle/_init_.py”, line 23, in switch_is_active

lms-1 | switch = get_waffle_switch_model().get(switch_name)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/waffle/models.py”, line 59, in get

lms-1 | obj = cls.get_from_db(name)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/waffle/models.py”, line 72, in get_from_db

lms-1 | return objects.get(name=name)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/models/manager.py”, line 87, in manager_method

lms-1 | return getattr(self.get_queryset(), name)(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/models/query.py”, line 633, in get

lms-1 | num = len(clone)

lms-1 | ^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/models/query.py”, line 380, in _len_

lms-1 | self._fetch_all()

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/models/query.py”, line 1881, in _fetch_all

lms-1 | self._result_cache = list(self._iterable_class(self))

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/models/query.py”, line 91, in _iter_

lms-1 | results = compiler.execute_sql(

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/models/sql/compiler.py”, line 1560, in execute_sql

lms-1 | cursor = self.connection.cursor()

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 330, in cursor

lms-1 | return self._cursor()

lms-1 | ^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 306, in _cursor

lms-1 | self.ensure_connection()

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 288, in ensure_connection

lms-1 | with self.wrap_database_errors:

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/utils.py”, line 91, in _exit_

lms-1 | raise dj_exc_value.with_traceback(traceback) from exc_value

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 289, in ensure_connection

lms-1 | self.connect()

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 270, in connect

lms-1 | self.connection = self.get_new_connection(conn_params)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/mysql/base.py”, line 247, in get_new_connection

lms-1 | connection = Database.connect(**conn_params)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/MySQLdb/_init_.py”, line 121, in Connect

lms-1 | return Connection(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/MySQLdb/connections.py”, line 200, in _init_

lms-1 | super()._init_(*args, **kwargs2)

lms-1 | django.db.utils.OperationalError: (1045, “Access denied for user ‘openedx’@‘172.18.0.8’ (using password: YES)”)

lms-1 | unable to load app 0 (mountpoint=‘’) (callable not found or import error)

lms-1 | *** no app loaded. GAME OVER ***

lms-1 | [uWSGI] getting INI configuration from /openedx/uwsgi.ini

lms-1 | [uwsgi-static] added mapping for /static => /openedx/staticfiles/

lms-1 | [uwsgi-static] added mapping for /media => /openedx/media/

lms-1 | *** Starting uWSGI 2.0.24 (64bit) on [Sat Oct 4 10:00:26 2025] ***

lms-1 | compiled with version: 11.4.0 on 23 September 2025 06:51:40

lms-1 | os: Linux-6.8.0-71-generic #71-Ubuntu SMP PREEMPT_DYNAMIC Tue Jul 22 16:52:38 UTC 2025

lms-1 | nodename: e478f2056851

lms-1 | machine: x86_64

lms-1 | clock source: unix

lms-1 | detected number of CPU cores: 2

lms-1 | current working directory: /openedx/edx-platform

lms-1 | detected binary path: /openedx/venv/bin/uwsgi

lms-1 | !!! no internal routing support, rebuild with pcre support !!!

lms-1 | your memory page size is 4096 bytes

lms-1 | detected max file descriptor number: 1048576

lms-1 | building mime-types dictionary from file /etc/mime.types…1516 entry found

lms-1 | lock engine: pthread robust mutexes

lms-1 | thunder lock: enabled

lms-1 | uWSGI http bound on 0.0.0.0:8000 fd 4

lms-1 | uwsgi socket 0 bound to TCP address 127.0.0.1:33525 (port auto-assigned) fd 3

lms-1 | Python version: 3.11.8 (main, Sep 2 2025, 08:09:41) [GCC 11.4.0]

lms-1 | Python main interpreter initialized at 0x7870032bd278

lms-1 | python threads support enabled

lms-1 | your server socket listen backlog is limited to 100 connections

lms-1 | your mercy for graceful operations on workers is 60 seconds

lms-1 | mapped 231048 bytes (225 KB) for 2 cores

lms-1 | *** Operational MODE: preforking ***

lms-1 | Traceback (most recent call last):

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 289, in ensure_connection

lms-1 | self.connect()

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/base/base.py”, line 270, in connect

lms-1 | self.connection = self.get_new_connection(conn_params)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/utils/asyncio.py”, line 26, in inner

lms-1 | return func(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/django/db/backends/mysql/base.py”, line 247, in get_new_connection

lms-1 | connection = Database.connect(**conn_params)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/MySQLdb/_init_.py”, line 121, in Connect

lms-1 | return Connection(*args, **kwargs)

lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

lms-1 | File “/openedx/venv/lib/python3.11/site-packages/MySQLdb/connections.py”, line 200, in _init_

lms-1 | super()._init_(*args, **kwargs2)

lms-1 | MySQLdb.OperationalError: (1045, “Access denied for user ‘openedx’@‘172.18.0.8’ (using password: YES)”)

Similiar problems found and what I have tried

  • As described in these posts (here and here) I removed the data folder in $(tutor config printroot) and in addition to that removed all containers and volumes. But after running `tutor local launch` the problem persists …

Steps for easy reproduction

These are all steps after spinning up a fresh ubuntu server (on digital ocean)

  1. create a non-root user
    1. adduser openedx
      
    2. (optional) copy the ssh-key from the root-user to the newly created user, to make it possible
      to login passwordless via ssh-key

    3. mkdir -p /home/openedx/.ssh
      chmod 700 /home/openedx/.ssh
      cp /root/.ssh/authorized_keys /home/openedx/.ssh/authorized_keys
      chown -R openedx:openedx /home/openedx/.ssh
      chmod 600 /home/openedx/.ssh/authorized_keys
      
    4. add to sudo group (temporary)
      usermod -aG sudo "openedx"

  2. docker installation (based on docker documentation)
    1. # Add Docker's official GPG key:
      sudo apt-get update
      sudo apt-get install ca-certificates curl
      sudo install -m 0755 -d /etc/apt/keyrings
      sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
      sudo chmod a+r /etc/apt/keyrings/docker.asc
      
      # Add the repository to Apt sources:
      echo \
        "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
        $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
        sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
      sudo apt-get update
      
    2. sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
      
    3. sudo usermod -aG docker openedx
      
  3. Now logout and loggin as the new created user called openedx
  4. install python
    1. sudo apt install python3 python3-pip libyaml-dev -y
      sudo apt install python3-venv -y
      python3 -m venv .venv
      source .venv/bin/activate
      
    2. Now install Tutor
      pip install "tutor[full]==20.0.1"

  5. Now after running tutor local launch the website should be accessible… but it is not due the exceptions thrown by CMS and LMS (logs can be seen by running `tutor local logs cms` and are attached above this section and described in detailed at the top of this post.)

Thank you in advance for your support and helpful answers!

Hi @attamirza
As far as I can tell, the overall process you’ve followed appears correct and should work.
Can you please confirm your system specifications? (hosting environment like a VPS, AWS services, on-premises self-host, etc; and system specs like RAM, CPU, Storage, etc)
I noticed in the logs you have 2x CPU cores, which ordinarily should be fine, but perhaps you have too little RAM? That might cause some of the issues you’re having if there’s too little RAM to start up all the containers…

I do have the same environment. Then I saw that the python virtual environment is not a must. So I downgraded to python 3.12 and did not initiate virtual environment. Same issue stays.

Then I downloaded pre compiled tutor from the git page. It is running perfect.

Hope it helps you too.

1 Like

Thank you very much @Ozgur_Yilmaz! Your approach works indeed. The only catch is that the pre compiled tutor version does not support custom plugins according to the documentation (see). We are using custom plugins, for example to inject our own SSL certificate, and so on.
Therefore we can’t use the pre compiled tutor version.

EDIT: The same issue mentioned above sometimes also occurs with the pre compiled version of Tutor.

I tried it on the following machines:

  • Ubuntu 24.0.4 on Digital Ocean with 4GB RAM and 2 CPU
    • (the above logs were from this machine)
  • Ubuntu 24.0.4 on Digital Ocean with 16GB RAM and 8 CPU
  • Ubuntu 24.0.4 on IONOS with 8GB RAM and 4 Cores
    • (The actual production server)
  • Ubuntu 24.0.4 on AWS with 8GB RAM and 4 CPU
  • Macbook Pro 24GB RAM with 14 Cores

The exact same problem occurred repeatedly on all these machines.

The MySQL one is typically something I used to encounter in low-memory machines. However, most of the machines you have shared seem to have the resources necessary. It’s very strange that this happens in multiple machines.

So, this is what I would do to debug:

  • pick the 16 GB Ubuntu Machine. That’s probably the best bet.
  • ensure the user has docker previleges. ie., can run containers without sudo
  • After a tutor launch, do a tutor local restart to re-establish connections
  • If the LMS/CMS still complain about authentication issues, grab the OPENEDX_MYSQL_PASSWORD from TUTOR_ROOT/config.yml and try to manually connect to the mysql container. Something like tutor local dc exec mysql mysql -u openedx -p<PASS> should drop you into the MySQL terminal, if it doesn’t that might indicate something. (I have no clue what that migt be :confused: )

I did a test on Ubuntu 24.0.4 (hyperv container with 4x CPU and 8GB RAM) and was able to replicate the issue. it appears to me at least that the openedx mysql user is not created. (cause unknown)

Hopefully this should get you to a working state:

grab the mysql passwords:
cat $(tutor config printroot)/config.yml | grep MYSQL

connect to root user:
tutor local dc exec mysql mysql -u root -pMYSQL_ROOT_PASSWORD (replace with actual password)

inspect users:
SELECT user, host FROM mysql.user;

+------------------+-----------+
| user             | host      |
+------------------+-----------+
| root             | %         |
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
+------------------+-----------+
5 rows in set (0.00 sec)

see openedx user missing

manually create user: (replace OPENEDX_MYSQL_PASSWORD with the correct value)

DROP USER IF EXISTS 'openedx'@'%';
CREATE USER 'openedx'@'%' IDENTIFIED BY 'OPENEDX_MYSQL_PASSWORD'; 
GRANT ALL PRIVILEGES ON *.* TO 'openedx'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;

initialise platform:
tutor local do init

wait for init and then restart:
tutor local stop && tutor local start -d

sanity check that all containers are running:
tutor local status

see if you can access your instance, hopefully should be working now. as for the actual issue, I haven’t determined a cause, only replicated the failure, this might require deeper inspection to see why it failed to create openedx user

3 Likes

Hey @tutor-maintainers looks like maybe there’s a bug here that can be reproduced that could be looked into?

Hi @sarina, @attamirza did log an issue on the git page a couple days ago, which I also linked back to this conversation for context, hopefully that should get more eyes on the issue :slight_smile:

1 Like

I had the same issue the solution of @joel.edwards worked
Thanks

1 Like