Archive note, October 2025: This describes one
ISPConfig installation and the naming confusion I encountered while
copying a production WordPress database into Docker.
The local WordPress environment was running. The database container
was healthy. My credentials came from a working production site.
Then the export failed:
ERROR 1044: Access denied for user ...
The database appeared not to exist under the name I had copied from
the WordPress configuration. The credentials were not wrong. I was
looking at the wrong layer of the hosting system.
The missing prefix
ISPConfig is designed to manage multiple clients on one server. It
prefixes resources so two clients can choose the same friendly database
name without colliding.
Conceptually, the server looked like this:
Client 1
c1socalnomaddb
c1socalnomadusr
Client 2
c2clientdb
c2clientusr
The WordPress configuration and ISPConfig interface did not initially
make the distinction obvious to me. I was thinking in terms of the
friendly name. MariaDB was enforcing the actual prefixed account and
database names.
The useful lesson was simple: when a control panel manages database
identities, do not assume the name displayed in one application is the
exact server-level name required by every administrative tool.
Finding the authoritative
name
There were several ways to verify it.
The safest was ISPConfig itself: open Sites →
Databases and inspect the full database and user names.
From the server, an administrator could also list matching
databases:
SHOW DATABASES LIKE '%socalnomad%';
The result exposed the c1 prefix.
The ISPConfig filesystem follows a related pattern. A site’s
human-readable path may be a symlink:
/var/www/example.com
-> /var/www/clients/client1/web11
The friendly domain path is easier for humans; the
client1/web11 path reflects ISPConfig’s internal ownership
model. Database naming follows the same general idea.
Exporting
without putting passwords in scripts
My early import script prompted for the production password and
interpolated it into a remote shell command. It worked, but embedding
passwords in command lines is undesirable: quoting is fragile, and
process lists or shell history can expose more than expected.
A better pattern is to use credentials already secured on the server,
a restricted defaults file, or WP-CLI under the site’s operating-system
account:
ssh user@example-server \
'wp --path=/var/www/example.com/web db export -' \
> production.sql
That keeps database credential handling inside WordPress and the
server configuration.
The local import remains straightforward:
docker exec -i my-wp-db \
mariadb -u wpuser -plocal_only_password wordpress_local \
< production.sql
The production name and the local name do not need to match. The dump
contains schema and data; the import target is whichever local database
WordPress is configured to use.
Rewriting the site URL
After import, WordPress still believed it lived at the production
domain.
Updating only home and siteurl may make the
dashboard accessible, but URLs can also appear inside post content,
widget settings, and serialized options. WP-CLI is the safer general
tool:
docker exec my-wp \
wp search-replace \
'https://example.com' \
'http://localhost:8080' \
--all-tables \
--skip-columns=guid
The guid column is normally left unchanged because it is
an identifier, not a display URL.
Why the import still was
not finished
Once the database loaded, production plugins and settings arrived
with it:
- Security plugins expected production IP addresses and authentication
flows. - Caching plugins could hide local changes.
- Email and analytics integrations could accidentally contact external
services. - Media references still pointed to files that were not part of the
database.
A database import is not the same thing as a complete local clone. It
is a starting point that needs an environment-specific cleanup pass.
For my setup, that meant:
- Confirm the full ISPConfig database identity.
- Export through the server’s trusted configuration.
- Import into the local MariaDB container.
- Rewrite production URLs.
- Disable or reconfigure production-only integrations.
- Verify the theme against representative content.
The broader lesson
The c1 prefix was not an arbitrary obstacle. It was
evidence that I was crossing boundaries between three different naming
systems:
- WordPress application configuration
- ISPConfig’s client-facing resource model
- MariaDB’s actual server accounts and databases
The import failed because I treated those layers as if they were
one.
Once I stopped asking, “Why is this password wrong?” and started
asking, “Which system owns this name?”, the problem became much easier
to solve.