Laravel `artisan migrate` Error: `SQLSTATE[42S02]: Base table or view not found` on Ubuntu 20.04 LTS

Resolve the Laravel `SQLSTATE[42S02]` error during `artisan migrate` on Ubuntu 20.04 LTS. This guide covers database connection, permissions, caching, and Docker-related fixes.


Resolve the Laravel `SQLSTATE[42S02]` error during `artisan migrate` on Ubuntu 20.04 LTS. This guide covers database connection, permissions, caching, and Docker-related fixes.

This troubleshooting guide addresses a common Laravel error encountered when attempting to run database migrations, specifically "SQLSTATE[42S02]: Base table or view not found". This error typically indicates that Laravel cannot locate or access the expected database or a specific table within it, preventing successful schema evolution. It's a critical issue that halts development and deployment processes, often pointing to misconfigurations in database connectivity or permissions.

Symptom & Error Signature

When you execute the php artisan migrate command from your Laravel project's root directory, instead of a successful migration message, you will observe an error similar to the following in your terminal:

php artisan migrate

   IlluminateDatabaseQueryException

  SQLSTATE[42S02]: Base table or view not found: 1146 Table 'your_database.migrations' doesn't exist (SQL: select `migration` from `migrations` order by `batch` asc, `migration` asc)

  at vendor/laravel/framework/src/Illuminate/Database/Connection.php:712
    708|         // If an exception occurs when attempting to run a query, we'll format the error
    709|         // message to include the bindings with the query, which will make debugging
    710|         // the data a lot easier if these errors tend to pop up a lot.
    711|         catch (Exception $e) {
    712|             throw new QueryException(
    713|                 $query, $this->prepareBindings($bindings), $e
    714|             );
    715|         }
    716|

  Exception trace:

  1   PDOException::("SQLSTATE[42S02]: Base table or view not found: 1146 Table 'your_database.migrations' doesn't exist")
      vendor/laravel/framework/src/Illuminate/Database/Connection.php:547

  2   PDOStatement::execute()
      vendor/laravel/framework/src/Illuminate/Database/Connection.php:547

The key parts of the error are SQLSTATE[42S02] and "Base table or view not found", often specifically mentioning the migrations table, or another table if you're running specific migrations on an existing, but possibly incomplete, database.

Root Cause Analysis

The SQLSTATE[42S02] error during artisan migrate fundamentally means Laravel couldn't find a table it expected to interact with. This can stem from several underlying issues:

  1. Incorrect Database Configuration: The most frequent cause. The .env file contains incorrect credentials (DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD), leading Laravel to attempt connection to a non-existent, wrong, or inaccessible database server/database schema.
  2. Database Not Created: The database specified by DB_DATABASE in your .env file simply does not exist on your MySQL or PostgreSQL server. Laravel tries to connect to it but finds no such schema.
  3. Insufficient Database User Permissions: The DB_USERNAME user specified in .env lacks the necessary privileges (e.g., CREATE, ALTER, DROP) to create tables in the specified DB_DATABASE.
  4. Configuration Cache Issues: Laravel caches its configuration for performance. If you've recently changed your .env file, especially database credentials, the cached configuration might still be pointing to old, invalid settings.
  5. Missing PHP Database Extensions: The required PHP Data Objects (PDO) extension for your database type (e.g., php-mysql or php-pgsql) is not installed or enabled for your PHP version.
  6. Incorrect Working Directory: The php artisan migrate command is executed from a directory other than your Laravel project root, causing it to fail to load the correct .env file or application context.
  7. Docker/Containerization Issues: When running Laravel in Docker, the database service might not be properly linked, reachable, or its hostname/port is incorrectly configured within the Laravel container's .env. Persistent volumes for the database might also be missing or misconfigured, leading to data loss on container restarts.

Step-by-Step Resolution

Follow these steps sequentially to diagnose and resolve the SQLSTATE[42S02] error.

1. Verify Database Existence and Connectivity

First, confirm that the target database actually exists on your database server and that you can connect to it.

  1. Check .env file: Open your Laravel project's .env file and note the DB_CONNECTION, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, and DB_PASSWORD values.
    DB_CONNECTION=mysql # or pgsql
    DB_HOST=127.0.0.1
    DB_PORT=3306 # or 5432 for PostgreSQL
    DB_DATABASE=your_laravel_db
    DB_USERNAME=your_db_user
    DB_PASSWORD=your_db_password
    
  2. Access your database server: Log in to your database server (e.g., via SSH to the machine hosting MySQL/PostgreSQL).
  3. Check database existence:
    • For MySQL:
      mysql -u your_db_user -p -h DB_HOST -P DB_PORT
      # Enter your_db_password when prompted
      SHOW DATABASES;
      USE your_laravel_db; # Attempt to select the database
      
    • For PostgreSQL:
      psql -U your_db_user -h DB_HOST -p DB_PORT -d your_laravel_db
      # Enter your_db_password when prompted
      l # List databases
      c your_laravel_db # Attempt to connect to the database
      
  4. Create database if missing: If your_laravel_db does not appear in the list of databases or you cannot connect to it, create it manually:
    • For MySQL: (Login as root or a privileged user)
      CREATE DATABASE your_laravel_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
      
    • For PostgreSQL: (Login as postgres or a privileged user)
      CREATE DATABASE your_laravel_db ENCODING 'UTF8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8' TEMPLATE template0;
      

    Ensure that the DB_HOST is correctly set. 127.0.0.1 or localhost is common for local/same-server databases. If your database is on a different server, use its IP address or hostname.

2. Inspect and Correct .env Database Credentials

Even if the database exists, incorrect credentials will prevent Laravel from accessing it.

  1. Re-verify .env: Double-check all database-related entries in your .env file against your actual database server configuration. Pay close attention to:

    • DB_HOST: Should be the IP or hostname of the database server.
    • DB_PORT: Default is 3306 for MySQL, 5432 for PostgreSQL.
    • DB_DATABASE: The exact name of the database.
    • DB_USERNAME: The username with access to DB_DATABASE.
    • DB_PASSWORD: The password for DB_USERNAME.
    • > [!WARNING] Ensure that passwords or usernames containing special characters (like #, $, !) are correctly escaped or quoted in your .env file if necessary, though Laravel generally handles this well. For robust passwords, consider avoiding some shell-special characters.
  2. Test connection with correct details: Attempt to connect to the database again using the exact values from your .env file, as shown in Step 1.

3. Ensure Database User Privileges

The DB_USERNAME user must have sufficient permissions to create, alter, and drop tables within your_laravel_db.

  1. Login to your database server as a privileged user: For example, as root for MySQL or postgres for PostgreSQL.
  2. Grant permissions:
    • For MySQL:
      -- If the user doesn't exist, create it first
      CREATE USER 'your_db_user'@'DB_HOST' IDENTIFIED BY 'your_db_password';
      -- Grant all privileges on your_laravel_db to the user
      GRANT ALL PRIVILEGES ON your_laravel_db.* TO 'your_db_user'@'DB_HOST';
      FLUSH PRIVILEGES;
      
      Replace DB_HOST with localhost, 127.0.0.1, or % (for any host – use with caution in production).
    • For PostgreSQL:
      -- Connect to the postgres default database
      c postgres
      -- If the user doesn't exist, create it first
      CREATE USER your_db_user WITH PASSWORD 'your_db_password';
      -- Grant all privileges on your_laravel_db to the user
      GRANT ALL PRIVILEGES ON DATABASE your_laravel_db TO your_db_user;
      

    Granting ALL PRIVILEGES is common for development. In production, consider granting only the minimum necessary privileges (SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, INDEX, REFERENCES) for better security.

4. Clear Laravel Configuration Cache

Laravel caches configuration files to speed up application loading. If you've recently modified .env, the cached version might be stale.

  1. Navigate to your Laravel project root:
    cd /var/www/html/your_laravel_app
    
  2. Clear caches:
    php artisan config:clear
    php artisan cache:clear
    php artisan view:clear
    # For Laravel 8+
    php artisan optimize:clear
    
  3. Attempt migration again:
    php artisan migrate
    

5. Install Missing PHP Database Extensions

Laravel relies on PHP's PDO extensions to communicate with databases. If these are missing, connections will fail.

  1. Identify your PHP version:
    php -v
    
    (e.g., PHP 7.4.3 or PHP 8.1.10)
  2. Install the correct PDO extension:
    • For MySQL:
      sudo apt update
      sudo apt install php7.4-mysql # Replace 7.4 with your PHP version (e.g., php8.1-mysql)
      
    • For PostgreSQL:
      sudo apt update
      sudo apt install php7.4-pgsql # Replace 7.4 with your PHP version (e.g., php8.1-pgsql)
      
  3. Restart PHP-FPM or Apache:
    • For Nginx with PHP-FPM:
      sudo systemctl restart php7.4-fpm.service # Adjust service name for your PHP version
      
    • For Apache:
      sudo systemctl restart apache2.service
      
  4. Verify extension: You can check if the extension is loaded:
    php -m | grep pdo_mysql # or pdo_pgsql
    
    It should output pdo_mysql or pdo_pgsql.

6. Check File Permissions

Incorrect file permissions on Laravel's storage and bootstrap/cache directories can prevent it from writing necessary files, sometimes leading to unexpected errors.

  1. Navigate to your Laravel project root:
    cd /var/www/html/your_laravel_app
    
  2. Set correct ownership and permissions: Assuming your web server user is www-data (common on Ubuntu) and your application root is /var/www/html/your_laravel_app:
    sudo chown -R www-data:www-data /var/www/html/your_laravel_app
    sudo find /var/www/html/your_laravel_app -type d -exec chmod 755 {} ;
    sudo find /var/www/html/your_laravel_app -type f -exec chmod 644 {} ;
    sudo chmod -R 775 /var/www/html/your_laravel_app/storage
    sudo chmod -R 775 /var/www/html/your_laravel_app/bootstrap/cache
    

    The storage and bootstrap/cache directories, along with their contents, must be writable by the web server user. If you use a different user/group for your web server (e.g., a custom FPM pool user), adjust www-data accordingly.

7. If Using Docker/Docker Compose

When deploying with Docker, network connectivity and service naming are critical.

  1. Verify service names and network:
    • Open your docker-compose.yml file.
    • Ensure the DB_HOST in your Laravel container's .env (or environment variables in docker-compose.yml) matches the service name of your database container (e.g., db or mysql).
    • Example docker-compose.yml snippet:
      services:
        app:
          build: .
          environment:
            DB_HOST: db # This MUST match the database service name below
            DB_DATABASE: your_laravel_db
            DB_USERNAME: your_db_user
            DB_PASSWORD: your_db_password
          depends_on:
            - db
        db:
          image: mysql:8.0 # or postgres:12
          environment:
            MYSQL_DATABASE: your_laravel_db
            MYSQL_USER: your_db_user
            MYSQL_PASSWORD: your_db_password
            MYSQL_ROOT_PASSWORD: root_password
          volumes:
            - db_data:/var/lib/mysql
      volumes:
        db_data:
      
  2. Check database container status:
    docker-compose ps
    
    Ensure your database service (db or mysql) is Up.
  3. Test connectivity from inside the Laravel container:
    docker exec -it <your_laravel_app_container_name> bash
    php artisan tinker
    
    Inside tinker, try to connect:
    DB::connection()->getPdo();
    
    If successful, it should return a PDO object. If it throws an error, it indicates a connectivity issue from within the container.
  4. Rebuild and restart: Sometimes, container network issues can persist. A full rebuild and restart can help:
    docker-compose down --volumes
    docker-compose up --build -d
    
    Then, attempt php artisan migrate from within the Laravel container:
    docker exec -it <your_laravel_app_container_name> php artisan migrate
    

8. Verify Laravel Application Path

Ensure you are executing php artisan migrate from the root directory of your Laravel project, where the artisan script and .env file are located.

  1. Check current directory:
    pwd
    
  2. List files:
    ls -F
    
    You should see artisan, .env, app/, bootstrap/, config/, etc. If not, cd into the correct directory.

After performing these steps, re-run php artisan migrate. If the issue persists, carefully review your terminal output for any new error messages that might point to a different problem.