A PhotoPrism® Portal and its tenant instances share one database server. This guide describes how to use MariaDB Enterprise Server as that database — including running it under the MariaDB Enterprise Operator on Kubernetes/OpenShift — and how to connect it to the Portal.
PhotoPrism connects with the standard MariaDB/MySQL wire protocol and imposes no Enterprise-specific requirements. Any MariaDB 11.4+ server works; MariaDB Enterprise Server 11.8 (LTS) is the recommended baseline for production clusters.
Database Baseline
| Property | Detail |
|---|---|
| Version | MariaDB Enterprise Server 11.8, a long-term-support release with regular maintenance releases. |
| Protocol | Wire- and SQL-compatible drop-in for the community server; PhotoPrism’s Go driver connects unchanged. |
| Character set | utf8mb4. PhotoPrism pins collation utf8mb4_unicode_ci for table creation, so it only needs that collation to remain available. |
| Authentication | PhotoPrism supports mysql_native_password and caching_sha2_password. Keep PhotoPrism/Portal accounts on one of these — do not assign the PARSEC plugin to application accounts. |
| Storage engine | InnoDB (ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci). |
Deployment Topologies
Both topologies connect through the same Portal database settings:
- External MariaDB Enterprise. The database runs as a managed service or a separately operated cluster. Point the Portal’s
PHOTOPRISM_DATABASE_SERVERat that endpoint. This keeps the database lifecycle independent of the PhotoPrism release. - In-cluster, operator-managed. MariaDB Enterprise runs inside Kubernetes/OpenShift, declared as a
MariaDBcustom resource and managed by the MariaDB Enterprise Operator (provisioning, failover, backups, TLS). The Portal connects to the operator-created Service, directly or via MaxScale. This is recommended when you want platform-native lifecycle management.
Installing the Operator
On OpenShift, the MariaDB Enterprise (Kubernetes) Operator is Red Hat-certified and published on OperatorHub under the certified-operators catalog (OLM package mariadb-enterprise-operator, channel stable). A Helm install is also offered by MariaDB for plain Kubernetes.
- Pre-check (OpenShift):
oc get packagemanifests -n openshift-marketplace mariadb-enterprise-operator. - Install: create a
Subscription(cluster-wide viaopenshift-operators, or scoped via a customOperatorGroupwithtargetNamespaces). - Images come from the credentialed registry
docker.mariadb.com(operator,enterprise-server,maxscale, optional LDAP sidecar) and require a MariaDB Customer Download Token. Provide it via the cluster global pull secret or animagePullSecret. Air-gapped installs mirror these images to a private registry. - SCC (OpenShift): the operator and its operands run under
restricted-v2— non-root, arbitrary UID, dropped capabilities — so no privileged SCC grant is needed. Do not deploy the database intodefaultorkube-system.
Operator field names, resource-naming conventions, and TLS defaults vary by operator release. Confirm them against the exact operator version installed in your cluster before a production rollout.
Declaring the Database
The operator exposes custom resources (confirm the API group/version against your installed operator):
| Kind | Purpose |
|---|---|
MariaDB | Deploys a server or cluster (standalone, primary/replica, or Galera). Seeds root plus an initial user/database. |
Database | A logical database (schema). |
User | A database user; password supplied via a Secret reference. |
Grant | Privilege grants binding a user to a database. |
MaxScale | Query router/proxy with read-write splitting and automated failover. |
Generated passwords are stored in Kubernetes Secrets. Applications discover the endpoint through the operator-created Service DNS name (<service>.<namespace>.svc.cluster.local:3306); confirm the exact Service and Secret names with oc get svc,secret -n <db-namespace>.
Provisioning Models
The Portal can either provision tenant databases itself, or consume databases the operator provisions. Choose one.
Model 1 — Portal Auto-Provisioning (Recommended)
Preserves dynamic tenant onboarding: when a new tenant registers, the Portal creates its schema and user on demand.
- Create a privileged provisioning account in MariaDB Enterprise (a
User+GrantwithCREATE USER,CREATE, andGRANT OPTION, or the root account from theMariaDBCR’s root Secret) on a driver-compatible auth plugin. - Set the Portal’s
PHOTOPRISM_DATABASE_PROVISION_DSNto that account’s DSN in Gomysqlform:user:password@tcp(<db-service>.<namespace>.svc.cluster.local:3306)/. - Leave
PHOTOPRISM_DATABASE_PROVISION_PREFIXatcluster_, or set a per-environment value when staging and production share one server. - The Portal’s own database (
PHOTOPRISM_DATABASE_NAME, defaultphotoprism_portal) must already exist — create it with aDatabaseCR. Tenants leave their database settings blank and receive Portal-provisioned credentials at registration.
Model 2 — Operator-Provisioned (Static / GitOps)
Pre-create every database and user with Database / User / Grant CRs, set explicit database name, user, and password per release, and leave the provisioning DSN empty so the Portal does not attempt to create schemas. This trades dynamic onboarding for fully declarative, auditable database resources and avoids granting the Portal a privileged account.
Mapping Database Settings
| Setting | Source from the operator |
|---|---|
PHOTOPRISM_DATABASE_SERVER | MariaDB (or MaxScale) Service DNS + port, e.g. <svc>.<namespace>.svc.cluster.local:3306 |
PHOTOPRISM_DATABASE_NAME | The Database CR for this release (Portal default photoprism_portal) |
PHOTOPRISM_DATABASE_USER/PASSWORD | The User CR + its password Secret (or blank on tenants for Portal provisioning) |
PHOTOPRISM_DATABASE_PROVISION_DSN | DSN built from the privileged provisioning User/root Secret (Portal, Model 1) |
See Config Options for the full set of database variables.
Connection Routing & Proxy
Connect either directly to the MariaDB Service or through MaxScale, MariaDB Enterprise’s native router:
- Standalone (no proxy): point
PHOTOPRISM_DATABASE_SERVERdirectly at the MariaDB Service on3306. - MaxScale (recommended for HA topologies): point
PHOTOPRISM_DATABASE_SERVERat the MaxScale Service (SQL listener on3306; admin/REST API on8989). MaxScale routes provisioned accounts to the backend automatically — there is no separate account-sync step.
ProxySQL is not used with MariaDB Enterprise — MaxScale is the proxy. Leave any ProxySQL account-sync settings empty.
Transport Security (TLS)
The MariaDB Enterprise Operator can issue and rotate TLS certificates or consume a cert-manager issuer. Whether TLS is enforced by default depends on the operator version.
When PhotoPrism connects using the discrete server/user/password fields, it builds its DSN without a tls= parameter, so client-side TLS is not configured on that path. Options, in order of preference:
- In-cluster network security (default). Keep Portal↔database traffic on the pod network within one namespace and restrict access with NetworkPolicies. This is the pragmatic baseline for a single-namespace operator deployment.
- Encrypted client connections via a full DSN. PhotoPrism honors a complete
PHOTOPRISM_DATABASE_DSN(with a?query string) including atls=parameter.tls=skip-verifyencrypts without verifying the server certificate; verified TLS (tls=custom) additionally requires registering the operator CA bundle in-process. - Terminate at MaxScale. Enable TLS between MaxScale and the backend while the Portal connects to MaxScale. MaxScale cannot serve TLS and non-TLS on the same listener simultaneously.
Recommendation: start with option 1 plus NetworkPolicies, and move to a full DSN with a tls= parameter if you require verified client-to-database encryption.
PhotoPrism® Documentation
For more information on specific features, services and related resources, please refer to the other documentation available in our Knowledge Base and User Guide: