Troubleshooting Guide¶
This guide provides comprehensive troubleshooting information for the Neo4j Kubernetes Operator, covering both Neo4jEnterpriseCluster and Neo4jEnterpriseStandalone deployments.
Faster than working through this by hand
The kubectl-neo4j CLI automates most of what follows:
kubectl neo4j diagnose— start here. Names the Kubernetes-level cause: the pod that will not schedule, the container that was OOMKilled, the PVC that never boundkubectl neo4j status— what exists and what is unhealthy, in one viewkubectl neo4j explain <Kind>/<name>— what a condition means and what to do about itkubectl neo4j preflight— the cluster-side preconditions, before you applykubectl neo4j support-bundle— collect everything below into one redacted archivekubectl neo4j cypher <name>— a shell, without the Secret round-trip
Use this guide when you want to look at things yourself, or when the CLI is not installed.
Quick Reference¶
Diagnostic Commands¶
With the CLI, the whole block below collapses to three commands:
kubectl neo4j status # every Neo4j resource, and which need attention
kubectl neo4j diagnose # why the unhealthy ones are unhealthy
kubectl neo4j explain <Kind>/<name> # what a condition means and what to do
diagnose reads the pod, PVC, StatefulSet, Job and event layers that the rest of this
section reaches by hand, and it knows the operator's naming scheme and namespaces.
By hand¶
# Check deployment status
kubectl get neo4jenterprisecluster
kubectl get neo4jenterprisestandalone
kubectl get neo4jdatabase
# View detailed information
kubectl describe neo4jenterprisecluster <cluster-name>
kubectl describe neo4jenterprisestandalone <standalone-name>
kubectl describe neo4jdatabase <database-name>
# Check pod status
# Clusters
kubectl get pods -l neo4j.com/cluster=<cluster-name>
kubectl logs -l neo4j.com/cluster=<cluster-name>
# Standalone
kubectl get pods -l app=<standalone-name>
kubectl logs -l app=<standalone-name>
# Check events
kubectl get events --sort-by=.metadata.creationTimestamp
# Check operator logs
kubectl logs -n neo4j-operator-system -l control-plane=controller-manager --tail=-1
Common Port Forwarding Commands¶
# For clusters
kubectl port-forward svc/<cluster-name>-client 7474:7474 7687:7687
# For standalone deployments
kubectl port-forward svc/<standalone-name>-client 7474:7474 7687:7687
Common Issues and Solutions¶
1. Split-Brain Scenarios¶
Problem: Cluster nodes form multiple independent clusters¶
This is most common with TLS-enabled clusters where nodes fail to join during initial formation.
Quick Check:
# Check each node's view of the cluster
for i in 0 1 2; do
kubectl exec <cluster>-server-$i -- cypher-shell -u neo4j -p <password> "SHOW SERVERS" | wc -l
done
Solution: See the Split-Brain Recovery Guide — the top of that page has a one-screen quick reference for detection and manual override commands.
Quick Fix:
# Restart minority cluster nodes (orphaned pods)
kubectl delete pod <cluster>-server-1 <cluster>-server-2
2. Deployment Validation Errors¶
Problem: Single-Node Cluster Not Allowed¶
servers must be at least 2 for clustering. For single-node deployments, use Neo4jEnterpriseStandalone instead
(The CRD schema also enforces spec.topology.servers >= 2, so kubectl apply itself may reject a smaller value with the apiserver's own "should be greater than or equal to 2" message.)
Solution: Use the correct CRD for your deployment type:
For development/testing (single-node):
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jEnterpriseStandalone
metadata:
name: dev-neo4j
spec:
acceptLicenseAgreement: "eval"
image:
repo: neo4j
tag: "5.26-enterprise"
storage:
className: standard
size: "10Gi"
For production (minimum cluster):
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jEnterpriseCluster
metadata:
name: prod-cluster
spec:
acceptLicenseAgreement: "eval"
topology:
servers: 2 # Minimum required for clustering
image:
repo: neo4j
tag: "5.26-enterprise"
storage:
className: standard
size: "10Gi"
Problem: Invalid Neo4j Version¶
Solution: Update to a supported version:
Supported versions:
- Semver: any 5.26.x (5.26.x is the last semver LTS — no 5.27+ exists)
- Calver: 2025.01.0 and later; each operator release validates one anchor CalVer, and newer ones are best-effort
See Supported Neo4j Versions for what each track guarantees.
3. Pod Startup Issues¶
Problem: Pods Stuck in Pending State¶
kubectl neo4j diagnose reports the scheduler's own reason and what to do about it, and
kubectl neo4j preflight -f <manifest> catches the two usual causes — no node large
enough, or a StorageClass that does not exist — before you apply. By hand:
# Check pod events
kubectl describe pod <pod-name>
# Common causes:
# - Insufficient resources
# - Storage issues
# - Image pull issues
Solutions:
-
Check Resource Availability:
-
Verify Storage Class:
-
Check Image Pull:
Problem: Pods Crashing (CrashLoopBackOff)¶
kubectl neo4j diagnose distinguishes a crash loop from an OOMKill (exit 137) and names
the pod and container to read. By hand:
Common causes and solutions:
-
Memory Issues:
-
Configuration Issues:
-
License Issues:
4. Connectivity Issues¶
Problem: Cannot Connect to Neo4j¶
# Test connectivity
kubectl port-forward svc/<service-name> 7474:7474 7687:7687
curl http://localhost:7474
# Check service
kubectl get svc -l app.kubernetes.io/name=neo4j
kubectl describe svc <service-name>
Solutions:
-
Check Service Configuration:
-
Verify Network Policies:
-
Check TLS Configuration:
5. Cluster-Specific Issues¶
Problem: Cluster Formation Fails¶
# Check cluster status
kubectl get neo4jenterprisecluster <cluster-name> -o yaml
# Check individual pod logs
kubectl logs <cluster-name>-server-0
kubectl logs <cluster-name>-server-1
Solutions:
- 🔧 Verify LIST Discovery Configuration
The operator uses LIST discovery with static pod FQDNs (port 6000). Check the startup script in the cluster ConfigMap:
kubectl get configmap <cluster-name>-config -o yaml | grep -A 3 "resolver_type"
# Neo4j 5.26.x should show:
# dbms.cluster.discovery.resolver_type=LIST
# dbms.cluster.discovery.version=V2_ONLY
# dbms.cluster.discovery.v2.endpoints=<cluster>-server-0.<cluster>-headless.<ns>.svc.cluster.local:6000,...
# Neo4j 2025.x+ should show:
# dbms.cluster.discovery.resolver_type=LIST
# dbms.cluster.endpoints=<cluster>-server-0.<cluster>-headless.<ns>.svc.cluster.local:6000,...
-
Verify Cluster Topology:
-
Check Inter-Pod Communication:
# Test DNS resolution to headless service kubectl exec -it <pod-name> -- nslookup <cluster-name>-headless # Test V2 cluster port connectivity (port 6000 carries both V2 discovery # and tcp-tx; port 5000 is V1-only and is never used by this operator). kubectl exec -it <pod-name> -- nc -zv localhost 6000 kubectl exec -it <pod-name> -- nc -zv localhost 7000 # RAFT -
Verify Discovery Labels:
Problem: A server is down (Degraded)¶
Symptoms:
- The cluster is still Ready but its Degraded condition is True, naming
the missing servers.
- After the grace period (5 minutes; operator flag
--server-unavailable-grace, Helm serverUnavailableGrace) the phase turns
Degraded: status.ready is false and a ClusterDegraded Warning event is
raised.
- With a majority of servers lost, the phase is Forming with a
ClusterQuorumLost Warning.
The cluster keeps serving while it has a majority: users, roles, databases and backups keep reconciling against it. A rolling image upgrade or a plugin install waits until every server is back.
Diagnosis:
kubectl get neo4jenterprisecluster <cluster-name> \
-o jsonpath='{.status.phase}{"\n"}{range .status.conditions[?(@.type=="Degraded")]}{.message}{"\n"}{end}'
kubectl get pods -l neo4j.com/cluster=<cluster-name>
kubectl describe pod <cluster-name>-server-<n> # why the missing server is not running
kubectl neo4j diagnose Neo4jEnterpriseCluster/<cluster-name>
Solution: bring the named server back (fix what keeps its pod from running). See Server availability.
Problem: Scaling Issues¶
Solutions:
-
Verify Minimum Topology:
-
Check Resource Limits:
6. Standalone-Specific Issues¶
Problem: Standalone Pod Won't Start¶
# Check standalone status
kubectl get neo4jenterprisestandalone <standalone-name> -o yaml
# Check pod events
kubectl describe pod <standalone-name>-0
Solutions:
-
Check Standalone Configuration:
-
Verify Storage Configuration:
Problem: Migration from Cluster to Standalone¶
# Create backup first
kubectl apply -f backup.yaml
# Deploy standalone
kubectl apply -f standalone.yaml
# Restore data
kubectl apply -f restore.yaml
7. Performance Issues¶
Problem: Slow Query Performance¶
# Check resource usage
kubectl top pods
kubectl top nodes
# Check Neo4j Prometheus metrics. Requires spec.monitoring.enabled: true,
# which creates a dedicated <cluster-name>-metrics service exposing port 2004.
# Metrics live on port 2004 at /metrics, not on the 7474 HTTP port.
kubectl port-forward svc/<cluster-name>-metrics 2004:2004
# Access http://localhost:2004/metrics
Solutions:
-
Adjust Memory Settings:
-
Enable Query Logging:
-
Check Storage Performance:
8. Storage Issues¶
Problem: PVC Issues¶
kubectl neo4j diagnose reports any PVC that is not Bound and names its StorageClass;
kubectl neo4j preflight checks that the class exists — and that it allows expansion —
before you apply. By hand:
# Check PVC status
kubectl get pvc
kubectl describe pvc <pvc-name>
# Check storage class
kubectl get storageclass
Solutions:
-
Verify Storage Class:
-
Check Node Storage:
Problem: Data Corruption¶
Solutions:
-
Run Consistency Check:
-
Restore from Backup:
9. Backup and Restore Issues¶
Problem: Backup Job fails to start (ServiceAccount / permission errors)¶
Backups run as Kubernetes Jobs that execute neo4j-admin directly against a database — they do NOT exec into the Neo4j pods. Each Job runs under the neo4j-backup-sa ServiceAccount, which the operator creates automatically in the backup's namespace (and stamps with any workload-identity annotations from spec.storage.cloud.identity.autoCreate.annotations).
Solution: kubectl neo4j preflight Neo4jBackup/<name> -n <ns> checks this before the
first run — that the ServiceAccount carries a cloud-identity annotation, or that the
credentials Secret exists and holds every key the Job mounts. kubectl neo4j diagnose
reports a Job that has already failed. By hand:
# The operator auto-creates this ServiceAccount; no Role/RoleBinding is needed
# because the Job runs neo4j-admin directly, not via pods/exec.
kubectl get serviceaccount neo4j-backup-sa -n <ns>
# Inspect the backup Job and its pod
kubectl describe neo4jbackup <backup-name> -n <ns>
kubectl get jobs -n <ns> -l app.kubernetes.io/part-of=<backup-name>
Problem: Backup path not found¶
Neo4j 5.26+ requires backup destination path to exist. The operator's backup Job creates the directory automatically (mkdir -p is prepended to the command for PVC targets; cloud targets get a trailing slash for directory semantics).
Solution: inspect the backup Job's Pod log:
# The Job is named "<neo4jbackup-name>-backup" (one-shot) or
# "<neo4jbackup-name>-backup-cron-<timestamp>" (CronJob child; the
# runID in status.history is this Job name).
kubectl logs -n <ns> job/<job-name>
10. Security Issues¶
Problem: Authentication Failures¶
# Check auth secret
kubectl get secret <auth-secret> -o yaml
# Check Neo4j auth logs
kubectl logs <pod-name> | grep -i auth
Solutions:
-
Verify Admin Secret:
-
Check Password Policy: Set the Neo4j password-policy keys in
spec.config:
Problem: TLS Certificate Issues¶
# Check certificate status
kubectl get certificates
kubectl describe certificate <cert-name>
# Check cert-manager logs
kubectl logs -n cert-manager deployment/cert-manager
Solutions:
-
Verify Issuer:
-
Check Certificate Details:
-
TLS Cluster Formation Issues:
TLS-enabled clusters are prone to split-brain during initial formation. If you see partial cluster formation:
# Check for split clusters
kubectl exec <cluster>-server-0 -- cypher-shell -u neo4j -p <password> "SHOW SERVERS"
kubectl exec <cluster>-server-1 -- cypher-shell -u neo4j -p <password> "SHOW SERVERS"
Prevention: The operator already configures discovery and RAFT
membership timeouts with values tuned for in-cluster formation (including
the longer windows TLS clusters need) — there are no spec.config knobs you
need to set for this, and overriding the operator-managed cluster settings is
not supported.
See Split-Brain Recovery Guide for detailed recovery procedures.
11. Database Creation Issues¶
Problem: Neo4jDatabase Creation Fails¶
# Check database status
kubectl get neo4jdatabase <database-name> -o yaml
kubectl describe neo4jdatabase <database-name>
# Check events specific to the database
kubectl get events --field-selector involvedObject.name=<database-name>
Common causes and solutions:
-
Cluster Not Ready:
-
Topology Exceeds Cluster Capacity:
-
Invalid Configuration Conflicts:
Problem: Seed URI Database Creation Fails¶
# Check validation errors
kubectl describe neo4jdatabase <database-name>
# Check operator logs for seed URI specific errors
kubectl logs -n neo4j-operator-system -l control-plane=controller-manager --tail=-1 | grep -i seed
Common seed URI issues:
-
Authentication Failures:
-
URI Access Issues:
-
Invalid URI Format:
-
Point-in-Time Recovery Issues:
-
Performance Issues with Seed URI:
# Warning: Using dump file format. For better performance with large databases, consider using Neo4j backup format (.backup) instead. # Solution: Use .backup format for large datasets seedURI: "s3://my-backups/database.backup" # Instead of .dump # `seedConfig.config` is not a tuning surface for CloudSeedProvider (it only # carries S3SeedProvider options such as `region`); for large seeds, give the # server pods enough memory/CPU and a reliable path to the bucket.
Problem: Database Stuck in Creating State¶
# Check database status conditions
kubectl get neo4jdatabase <database-name> -o jsonpath='{.status.conditions[*].message}'
# Monitor database creation progress
kubectl get events -w --field-selector involvedObject.name=<database-name>
Solutions:
-
Check Cluster Connectivity:
-
Large Backup Restoration:
-
Network Connectivity Issues:
Problem: Database Ready But No Data¶
# Connect to database and check
kubectl exec -it <cluster-pod> -- cypher-shell -u neo4j -p <password> -d <database-name> "MATCH (n) RETURN count(n)"
Solutions:
-
Initial Data Not Applied:
-
Seed URI Data Not Restored:
Advanced Troubleshooting¶
Debug Mode¶
Enable debug logging in the operator by appending a flag to the manager's existing arguments (a plain strategic-merge patch of args would replace them all). The Deployment is named neo4j-operator for a Helm release called neo4j-operator, and neo4j-operator-controller-manager for kustomize installs:
kubectl get deployment -n neo4j-operator-system # find the operator Deployment name
kubectl patch deployment <operator-deployment> \
-n neo4j-operator-system --type=json \
-p '[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--zap-log-level=debug"}]'
For Helm installs, helm upgrade neo4j-operator ... --set logLevel=debug is the durable way (the chart renders --zap-log-level from logLevel).
Resource Monitoring¶
Monitor resource usage:
# Watch resource usage
watch kubectl top pods
watch kubectl top nodes
# Check resource limits
kubectl describe limitrange
kubectl describe resourcequota
Network Debugging¶
Test network connectivity:
# DNS resolution
kubectl exec -it <pod-name> -- nslookup <service-name>
# Port connectivity
kubectl exec -it <pod-name> -- telnet <service-name> 7687
# Network policies
kubectl get networkpolicies --all-namespaces
Collecting Diagnostic Information¶
When filing an issue, include the output of:
kubectl get neo4jenterprisecluster,neo4jenterprisestandalone -A
kubectl get pods,svc,pvc -l app.kubernetes.io/name=neo4j
kubectl get events --sort-by=.metadata.creationTimestamp | tail -30
kubectl logs -n neo4j-operator-system -l control-plane=controller-manager --tail=200
kubectl describe nodes | grep -A 5 "Allocated resources:"
Getting Help¶
Support Resources¶
- Documentation: User Guide
- API Reference: Neo4jEnterpriseCluster, Neo4jEnterpriseStandalone
- Upgrade Guide: Upgrade Guide
- Community: Neo4j Community Forum
- Issues: GitHub Issues
When to Contact Support¶
Contact support when:
- Data corruption is suspected
- Cluster formation consistently fails
- Performance is significantly degraded
- Security incidents occur
- Migration issues cannot be resolved
Always provide the diagnostic report and specific error messages when contacting support.