Troubleshooting

Common errors with their exact error messages and fixes. If your issue isn't listed here, check the server logs first — they almost always contain the real error.

Check the logs first

The logs contain the actual error in almost every case. Before anything else:

bash
# Docker docker compose logs -f app docker compose logs -f db # Bare-metal / systemd journalctl -u tether -f journalctl -u tether -n 100 # last 100 lines

Installation & startup issues

Error: Can't connect to MySQL server / Connection refused

error
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2003, "Can't connect to MySQL server on 'db' ([Errno 111] Connection refused)")

What it means: The app container started before MariaDB was ready to accept connections.

Fix: This usually resolves itself — the app retries on startup. If it persists:

bash
# Check if the database container is healthy docker compose ps # "tether-db" should show "healthy", not "starting" # If MariaDB is stuck starting, check its logs docker compose logs db # Restart both containers docker compose restart
Why this happens

Docker Compose starts containers in dependency order and waits for the healthcheck to pass, but on first boot MariaDB takes 15–30 seconds to initialise. The healthcheck in docker-compose.yml handles this, but sometimes the first boot takes longer than expected on slow machines.

Error: Access denied for user 'tether'@'...'

error
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1045, "Access denied for user 'tether'@'172.18.0.3' (using password: YES)")

What it means: The database credentials are wrong, or the MariaDB user was not created correctly.

Fix:

  1. Verify DB_PASSWORD in .env matches what was used to create the MariaDB user
  2. Check the MariaDB user exists:
    bash
    docker compose exec db mariadb -u root -p -e "SELECT User, Host FROM mysql.user;"
  3. If the user is missing, recreate it:
    bash
    docker compose exec db mariadb -u root -p -e " CREATE USER IF NOT EXISTS 'tether'@'%' IDENTIFIED BY 'yourpassword'; GRANT ALL PRIVILEGES ON tether.* TO 'tether'@'%'; FLUSH PRIVILEGES;"
The host wildcard % is required in Docker

In Docker, the app container connects from a different IP each time. The MariaDB user must allow connections from any host (%), not just localhost. Using 'tether'@'localhost' will fail in Docker.

Error: Unknown database 'tether'

error
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1049, "Unknown database 'tether'")

What it means: The database was never created.

Fix (Docker): The Docker Compose MariaDB service creates the database automatically using MARIADB_DATABASE. If it didn't:

bash
docker compose exec db mariadb -u root -p -e "CREATE DATABASE IF NOT EXISTS tether CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

Fix (bare-metal):

bash
sudo mysql -e "CREATE DATABASE tether CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

Error: jose.exceptions.JWTError / Invalid signature

error
jose.exceptions.JWTError: Signature verification failed.

What it means: The SECRET_KEY in .env changed after tokens were issued. All existing sessions are invalid.

Fix: This is expected behaviour — log in again. If you didn't intentionally change the key, check your .env file hasn't been reset to defaults.

Networking & subdomain issues

All subdomains show the MSP dashboard or wrong tenant

What it means: The Host header is not being passed through the reverse proxy correctly. Tether is seeing the proxy's hostname instead of the client's subdomain.

Fix: Ensure your nginx config includes:

nginx
proxy_set_header Host $host;

Then reload nginx:

bash
sudo nginx -t && sudo systemctl reload nginx

Client subdomain returns 404 or "tenant not found"

What it means: Either the DNS wildcard record isn't set, or the tenant slug doesn't match the subdomain.

Diagnose:

bash
# Check DNS resolves to your server dig acme.atechsolutions.org A +short # Should return your server's IP # Check the tenant slug matches # Log in as MSP admin and go to Clients — the slug shown must match exactly # "acme" slug → "acme.atechsolutions.org"

Browser shows certificate error on client subdomains

What it means: Your SSL certificate doesn't cover the subdomain. A standard (non-wildcard) certificate only covers the exact domain it was issued for.

Fix: You need a wildcard certificate covering *.atechsolutions.org. See Reverse proxy & HTTPS for setup instructions.

Login issues

Login fails with "Incorrect email or password"

Possible causes:

Reset password as MSP admin:

  1. Log in as MSP admin at the root domain
  2. Go to Users, find the user, click Edit
  3. Enter a new password and save

Forgot the MSP admin password and can't log in

If you've lost access to the only admin account:

bash
# Docker — connect to MariaDB and update the password hash directly # First, generate a bcrypt hash of your new password: docker compose exec app python3 -c " import bcrypt new_password = 'yournewpassword' hashed = bcrypt.hashpw(new_password.encode(), bcrypt.gensalt()).decode() print(hashed) " # Then update it in the database: docker compose exec db mariadb -u tether -ptether tether -e " UPDATE users SET password_hash='PASTE_HASH_HERE' WHERE email='[email protected]';"
Direct database editing is a last resort

Editing the database directly bypasses all validation. Only do this if you have truly lost all admin access. Change the password through the UI immediately after regaining access.

Asset and import issues

POST /api/assets returns 402 Payment Required

json
{"detail": "Asset limit reached for your Growth plan (1000/1000 assets). Please upgrade to add more."}

What it means: You are in SaaS mode (DEPLOYMENT_MODE=saas) and have reached your plan's asset limit.

Fix: Either upgrade the plan via PUT /api/billing/tier or delete some assets to make room. If you are running a self-hosted install and don't want limits, change DEPLOYMENT_MODE=selfhosted in .env and restart.

CSV import returns errors for some rows

Common causes and fixes:

Error messageCauseFix
Invalid status 'in use'Unrecognised status valueOnly available, deployed, maintenance, retired are valid
purchase_cost must be numericCost column contains textRemove currency symbols and text — use plain numbers like 1499 or 1499.00
Unrecognised date formatDate not in an accepted formatUse YYYY-MM-DD for consistency
asset_tag already existsDuplicate asset tag in the same CSVAsset tags must be unique per tenant within one import batch — deduplicate before importing

Import times out on large files

Imports of 500+ rows can take more than 60 seconds on slower servers, hitting the nginx proxy_read_timeout.

Fix: Split large imports into batches of ~500 rows, or increase the nginx timeout:

nginx
location /api/assets/import/ { proxy_pass http://127.0.0.1:8000; proxy_read_timeout 300s; # 5 minutes for large imports }

Performance issues

Asset list is slow to load

If the asset list takes more than 2–3 seconds to load, common causes are:

MariaDB: connection lost after idle period

error
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2006, 'MySQL server has gone away')

What it means: MariaDB closed an idle connection after wait_timeout (default 8 hours). The connection pool held an old connection that no longer works.

Fix: This is handled automatically by the pool_pre_ping=True and pool_recycle=3600 settings in Tether's database config. If you still see it, ensure DB_HOST is set (not using SQLite) so the pool settings are active. Restart the app container to clear stale connections:

bash
docker compose restart app

Docker-specific issues

Error: port is already allocated

error
Error response from daemon: driver failed programming external connectivity on endpoint tether-app: Bind for 0.0.0.0:8000 failed: port is already allocated

Fix: Something else is using port 8000. Either stop the conflicting service or change Tether's port in docker-compose.yml:

yaml
ports: - "8001:8000" # use port 8001 instead

Error: no space left on device

error
OSError: [Errno 28] No space left on device

Fix:

bash
# Check disk usage df -h # Free up Docker space (unused images, stopped containers, build cache) docker system prune # Check the size of Tether volumes docker system df -v

Error: Permission denied on volume mount

error
PermissionError: [Errno 13] Permission denied: '/data/tether.db'

Fix:

bash
# Fix ownership on the volume mount point docker compose exec app chown -R app:app /data

Getting help

If your issue isn't covered here:

  1. Search GitHub Issuesgithub.com/atechlab-am/tether/issues. Many issues have already been answered.
  2. Open a new issue — include the full error from your logs, your DEPLOYMENT_MODE, your database type, and your OS. Without these, it's very hard to help.
  3. Email support[email protected] for hosted instances or urgent issues.
Include your logs when asking for help

The most common reason we can't help quickly is missing logs. Always include the full error output from docker compose logs app or journalctl -u tether -n 100 when reporting an issue.

Last updated: May 2026