Devnote https://devnote.in/ Web Development Blog Company, Services India Tue, 02 Dec 2025 06:17:00 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://devnote.in/wp-content/uploads/2021/11/cropped-devnote-32x32.png Devnote https://devnote.in/ 32 32 173418453 Fix iOS Safari input type=”file” Not Opening Camera – Real Solution https://devnote.in/fix-ios-safari-input-typefile-not-opening-camera-real-solution/ https://devnote.in/fix-ios-safari-input-typefile-not-opening-camera-real-solution/#respond Mon, 16 Feb 2026 06:13:05 +0000 https://devnote.in/?p=5531 You add an <input type="file">, test on desktop, everything works.Then you open the page on an iPhone, tap the field in Safari, and nothing useful happens: This is a classic iOS Safari headache. The good news is that it is usually caused by a few specific things in your HTML, JavaScript, or Safari permissions. In […]

The post Fix iOS Safari input type=”file” Not Opening Camera – Real Solution appeared first on Devnote.

]]>
You add an <input type="file">, test on desktop, everything works.
Then you open the page on an iPhone, tap the field in Safari, and nothing useful happens:

  • No camera option
  • Only Files app appears
  • Or the picker does not open at all

This is a classic iOS Safari headache. The good news is that it is usually caused by a few specific things in your HTML, JavaScript, or Safari permissions. In this guide, we will fix it step by step with real, tested solutions.

1. How iOS Safari decides whether to show the camera

On iOS, Safari looks at three things:

  1. The input type: type="file"
  2. The accept attribute
  3. The capture attribute (optional hint for using the camera)

If you do not tell Safari that you want an image or video, it is free to open only the Files picker. If you hide the element or trigger it incorrectly with JavaScript, Safari may even refuse to open the picker at all.

So the first step is to fix the markup.

2. Correct HTML for opening the camera

Use this as your base:

<input
  type="file"
  accept="image/*"
  capture="environment"
>

What each attribute does:

  • type="file" – tells Safari this is a file picker.
  • accept="image/*" – tells Safari you want images, so it can show the camera and photo library.
  • capture="environment" – hints that you want the back camera (you can also use "user" for the front camera).

On most modern iPhones, this combination shows a sheet with options like:

  • Take Photo or Video
  • Photo Library
  • Browse

If your input did not have accept or used something generic like */*, Safari might not show the camera option at all.

For video capture

<input
  type="file"
  accept="video/*"
  capture="environment"
>

3. Do not hide the input in a tricky way

A lot of UI libraries hide the <input> and use a styled button that calls input.click() in JavaScript. Desktop browsers usually accept this, but iOS Safari is stricter.

Rules that iOS expects:

  • The file picker must be triggered by a real user gesture (tap, click).
  • That gesture must directly trigger input.click() in the same event stack.
  • If the input is completely off screen or has display:none, Safari can refuse to open the picker.

Safe pattern using a <label>

The most reliable way is to keep the input on the page and link it to a label:

<input
  type="file"
  id="photo-input"
  accept="image/*"
  capture="environment"
  style="position: absolute; left: -9999px;"
>

<label for="photo-input" class="upload-button">
  Upload or Take Photo
</label>

Here:

  • The input is visually hidden but still in the document.
  • The label is clickable and natively focuses the file input.
  • No JavaScript is required to open the picker, which iOS likes.

If you really want to use JavaScript, make sure it is triggered directly from a tap handler:

const input = document.getElementById('photo-input');
const button = document.getElementById('open-camera');

button.addEventListener('click', () => {
  // Must be directly in this click handler
  input.click();
});

Avoid wrapping this input.click() inside setTimeout, Promise.then, or other async functions, because iOS may treat it as non user-initiated and block it.

4. Check iOS Safari camera permissions

Even with perfect HTML, Safari will not open the camera if the site does not have permission.

Reset camera access for your site

On the iPhone:

  1. Open Settings.
  2. Scroll to Safari.
  3. Tap Camera.
  4. Make sure it is set to Ask or Allow (not Deny).

If you already denied access once, Safari remembers it and silently blocks camera use, which looks like the file input is broken.

You can also reset website permissions:

  1. In Safari, open your site.
  2. Tap the aA icon in the address bar.
  3. Choose Website Settings.
  4. Ensure Camera is set to Ask or Allow.

Then reload the page and tap the input again.

5. Serve your page over HTTPS when possible

From a security angle, iOS is much happier to allow camera access on secure origins.

  • For local development, use https://localhost if you can.
  • For production, always use HTTPS.

It often still works on plain HTTP, but some setups and third party browsers on iOS enforce stricter rules.

If you are building a PWA or adding the site to the home screen, HTTPS is basically required anyway, and that will make camera access more reliable.

6. Fix broken combinations of multiple attributes

Sometimes the problem is not the camera itself, but a confusing input configuration. Examples:

  • multiple combined with some older capture hacks
  • accept="image/*,application/pdf" on iOS versions that hate mixed types
  • Custom input validation that prevents the change event from firing

If you only need the camera or photos, start as simple as possible:

<input
  type="file"
  accept="image/*"
  capture="environment"
>

Test that on a real iPhone.
If it works, add extra options one by one:

<input
  type="file"
  accept="image/*,video/*"
  capture="environment"
  multiple
>

If the camera stops appearing after adding something, you have found the culprit.

7. Debugging checklist

Here is a quick list you can go through when the input still does not open the camera on iOS:

  1. HTML attributes
    • Do you have accept="image/*" or accept="video/*"?
    • Are you using capture="environment" or capture="user" if you want camera first?
  2. Element visibility
    • Is the <input> in the DOM and not display:none?
    • If it is visually hidden, are you using a label or a safe JS click() from a user event?
  3. JavaScript
    • Is input.click() called directly in the tap handler, not inside async code?
    • Are you preventing default on the click in some global handler that blocks it?
  4. Permissions
    • In iOS settings, is Safari allowed to use the camera?
    • In Safari website settings, is your domain allowed to use the camera?
  5. Protocol
    • Is the site running over HTTPS, especially for PWAs or production?

Once you go through these points, 99 percent of “input file not opening camera on iOS Safari” cases are solved.

Conclusion

When <input type="file"> does not open the camera on iOS Safari, it is almost never a random bug. It is usually one of these:

  • Missing or wrong accept / capture attributes
  • Hidden or programmatically triggered input that iOS does not trust
  • Camera permission blocked for Safari or that specific site

Use the simple, standards-based markup, trigger the input from a real user gesture, and confirm Safari has permission to use the camera. After that, your users will finally be able to tap the field, open the camera, and upload photos without weird workarounds.

The post Fix iOS Safari input type=”file” Not Opening Camera – Real Solution appeared first on Devnote.

]]>
https://devnote.in/fix-ios-safari-input-typefile-not-opening-camera-real-solution/feed/ 0 5531
MySQL Error 121 Duplicate key on write – Practical Repair Strategy https://devnote.in/mysql-error-121-duplicate-key-on-write-practical-repair-strategy/ https://devnote.in/mysql-error-121-duplicate-key-on-write-practical-repair-strategy/#respond Fri, 13 Feb 2026 08:42:12 +0000 https://devnote.in/?p=5527 ERROR 121: Duplicate key on write or update usually appears when you run an INSERT, UPDATE, or when MySQL is applying a foreign key or index change. The message is short and confusing, but the meaning is simple: MySQL is trying to create, update, or use a key that already exists where it must be […]

The post MySQL Error 121 Duplicate key on write – Practical Repair Strategy appeared first on Devnote.

]]>
ERROR 121: Duplicate key on write or update usually appears when you run an INSERT, UPDATE, or when MySQL is applying a foreign key or index change. The message is short and confusing, but the meaning is simple: MySQL is trying to create, update, or use a key that already exists where it must be unique. In this guide we will focus on practical ways to find the real conflict and fix it safely without guessing.

1. Understand when Error 121 appears

You might see the error in these situations:

  • During INSERT or UPDATE on a table with a unique index.
  • When running ALTER TABLE to add or change an index.
  • When creating a foreign key constraint.
  • When importing a dump or running migrations.

Typical error text:

ERROR 121 (HY000): Duplicate key on write or update

The key can be:

  • A PRIMARY KEY
  • A UNIQUE index
  • A foreign key constraint internally mapped to an index

2. First check: duplicate primary or unique index values

Most of the time, the problem is simply duplicate data in a column that must be unique.

Step 1: Find the unique indexes

Run:

SHOW INDEX FROM your_table;

Look for rows where Non_unique = 0. Those indexes require unique values.

Step 2: Search for duplicates

Assume the unique index is on column email:

SELECT email, COUNT(*) AS cnt
FROM your_table
GROUP BY email
HAVING cnt > 1;

If you see rows with cnt > 1, that is your conflict.

Step 3: Clean or merge duplicates

You can:

  • Keep the newest row and delete older ones.
  • Merge data into one row.
  • Change the conflicting value.

Example: delete duplicates and keep the smallest id:

DELETE t1
FROM your_table t1
JOIN your_table t2
  ON t1.email = t2.email
 AND t1.id > t2.id;

Run your original query again after cleaning.

3. When the error comes from AUTO_INCREMENT

Sometimes the auto increment value jumps into an existing id and causes error 121.

Example:

  • Table id column is AUTO_INCREMENT PRIMARY KEY
  • You manually inserted an id bigger than the current auto increment
  • Or you imported data and the auto increment value was not updated

Step 1: Check the current max id

SELECT MAX(id) FROM your_table;

Step 2: Fix the AUTO_INCREMENT value

If MAX(id) is 500 and MySQL will try to use 400, then bump it:

ALTER TABLE your_table AUTO_INCREMENT = 501;

Now future inserts will not clash.

4. Duplicate key when adding a new unique index

You might see error 121 while running:

ALTER TABLE users ADD UNIQUE (email);

MySQL fails because some rows already have the same email.

Step 1: Find conflicts before adding the index

SELECT email, COUNT(*) AS cnt
FROM users
GROUP BY email
HAVING cnt > 1;

Fix or delete those duplicate rows.

Step 2: Add the index again

ALTER TABLE users ADD UNIQUE (email);

If it runs successfully, the error is gone.

5. Duplicate key from foreign key constraints

This one is a bit trickier. Error 121 can also appear when MySQL tries to create a foreign key and a conflicting index already exists internally.

Typical cases:

  • Two foreign keys with the same name.
  • An old leftover constraint from a previous migration.
  • InnoDB trying to auto-create an index with a duplicate name.

Step 1: List foreign keys and their names

Run:

SHOW CREATE TABLE child_table\G

Look for lines like:

CONSTRAINT `fk_child_parent` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`)

Foreign keys (and their internal indexes) must have unique names within the same database.

Step 2: Rename the new foreign key

If you are adding a foreign key and its name already exists, simply change the name:

ALTER TABLE child_table
  ADD CONSTRAINT fk_child_parent_2
  FOREIGN KEY (parent_id)
  REFERENCES parent(id);

Or drop the old one first if it is not needed:

ALTER TABLE child_table
  DROP FOREIGN KEY fk_child_parent;

Then add your new constraint.

6. Duplicate key due to orphaned data

If the foreign key uses ON UPDATE or ON DELETE rules, you can also hit the error when inserting inconsistent data.

Example:

  • orders.customer_id references customers.id
  • You are inserting an order with customer_id = 10
  • There is no record with id = 10 in customers

This usually causes foreign key errors, but in some mixed setups you might hit error 121.

Step 1: Check orphaned rows

SELECT o.*
FROM orders o
LEFT JOIN customers c ON o.customer_id = c.id
WHERE c.id IS NULL;

Fix by:

  • Inserting missing customers,
  • Or updating/removing orphaned orders.

7. Using SHOW ENGINE INNODB STATUS for more detail

If you still cannot see the cause, InnoDB can tell you more.

Immediately after the error runs:

SHOW ENGINE INNODB STATUS\G

In the “LATEST FOREIGN KEY ERROR” section, you will often see:

  • Which table and index is conflicting
  • The exact key name MySQL fails on

That usually points directly to the table/column to inspect.

8. Safe repair workflow (step-by-step)

Here is a small strategy you can follow on any project.

  1. Identify the statement
    Note which INSERT, UPDATE, or ALTER TABLE caused the error.
  2. Check indexes on the target table SHOW INDEX FROM your_table;
  3. Search for duplicates on unique columns SELECT col, COUNT(*) FROM your_table GROUP BY col HAVING COUNT(*) > 1;
  4. Fix duplicates
    • Decide which rows to keep.
    • Delete or update the rest.
  5. Review AUTO_INCREMENT SELECT MAX(id) FROM your_table; ALTER TABLE your_table AUTO_INCREMENT = <max + 1>;
  6. Inspect foreign keys (if involved) SHOW CREATE TABLE your_table\G
  7. Check InnoDB status if still stuck SHOW ENGINE INNODB STATUS\G
  8. Run the original query again
    Confirm no more error 121 appears.

9. Preventing Duplicate key errors in the future

Once you have cleaned things up, add these habits:

  • Use proper unique indexes early in the schema design.
  • Validate data in your application layer before inserting.
  • Avoid manual edits that bypass existing constraints.
  • Keep consistent foreign key names in migrations.
  • Run integrity checks regularly on important tables.

Wrap up

MySQL error 121 “Duplicate key on write” looks scary, but it always boils down to the same thing: the database is trying to keep a key unique, and your operation breaks that rule.

By:

  • Checking unique indexes,
  • Cleaning duplicate rows,
  • Fixing AUTO_INCREMENT,
  • And reviewing foreign keys,

you can repair the problem in a structured, safe way instead of randomly changing constraints.

The post MySQL Error 121 Duplicate key on write – Practical Repair Strategy appeared first on Devnote.

]]>
https://devnote.in/mysql-error-121-duplicate-key-on-write-practical-repair-strategy/feed/ 0 5527
PHP cURL error 60: SSL certificate problem – Windows & Linux Fix https://devnote.in/php-curl-error-60-ssl-certificate-problem-windows-linux-fix/ https://devnote.in/php-curl-error-60-ssl-certificate-problem-windows-linux-fix/#respond Wed, 11 Feb 2026 08:17:39 +0000 https://devnote.in/?p=5522 If you are working with APIs in PHP and suddenly see: cURL error 60: SSL certificate problem: unable to get local issuer certificate it means PHP cannot verify the SSL certificate from the server you are requesting. This is extremely common on Windows setups (XAMPP, WAMP) and fresh Linux servers. The fix is straightforward once […]

The post PHP cURL error 60: SSL certificate problem – Windows & Linux Fix appeared first on Devnote.

]]>
If you are working with APIs in PHP and suddenly see: cURL error 60: SSL certificate problem: unable to get local issuer certificate it means PHP cannot verify the SSL certificate from the server you are requesting. This is extremely common on Windows setups (XAMPP, WAMP) and fresh Linux servers.

The fix is straightforward once you understand what is missing: a trusted CA certificate bundle.

Why does cURL error 60 happen?

PHP uses cURL to make HTTPS requests. cURL checks server certificates against a list of trusted Certificate Authorities (CA). If PHP cannot find that list, it refuses the connection for security reasons. So the real issue is not your code, but your environment.

Fix on Windows (XAMPP / WAMP / PHP standalone)

Step 1: Download the CA bundle

Use the official curl project CA bundle:
https://curl.se/ca/cacert.pem

Save it somewhere stable, for example:

C:\xampp\php\extras\ssl\cacert.pem

Step 2: Edit php.ini

Open php.ini and find this line:

;curl.cainfo =

Uncomment and set the path:

curl.cainfo = "C:\xampp\php\extras\ssl\cacert.pem"

Also locate:

;openssl.cafile=

Set it too:

openssl.cafile="C:\xampp\php\extras\ssl\cacert.pem"

Restart Apache or PHP.

That’s it. cURL will now trust valid SSL certificates.

Fix on Linux (Ubuntu, Debian, CentOS, etc.)

Linux usually includes default CA packages. Install or update them:

Ubuntu / Debian

sudo apt-get update
sudo apt-get install ca-certificates
sudo update-ca-certificates

CentOS / RedHat / AlmaLinux

sudo yum install ca-certificates
sudo update-ca-trust force-enable
sudo update-ca-trust extract

After installation, PHP will automatically use the system’s CA store.

Using HTTPS inside Docker or CI

Many CI images are trimmed and do not include SSL bundles.

Simply install them:

apt-get update
apt-get install -y ca-certificates

Then rebuild your image.

You will see developers do this:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

It disables SSL verification and opens huge security risks.
Only use this for debugging local issues, never in production.

Quick checklist

If you still get the same error:

  • Did you restart Apache, Nginx, or PHP-FPM?
  • Is your php.ini the CLI one or the web one?
  • Are you editing the correct PHP version (7.4 vs 8.2)?
  • Is the CA file readable (correct path, no typos)?

The post PHP cURL error 60: SSL certificate problem – Windows & Linux Fix appeared first on Devnote.

]]>
https://devnote.in/php-curl-error-60-ssl-certificate-problem-windows-linux-fix/feed/ 0 5522
Fix “localhost refused to connect” After Installing XAMPP / WAMP https://devnote.in/fix-localhost-refused-to-connect-after-installing-xampp-wamp/ https://devnote.in/fix-localhost-refused-to-connect-after-installing-xampp-wamp/#respond Mon, 09 Feb 2026 08:01:09 +0000 https://devnote.in/?p=5518 You install XAMPP or WAMP, open your browser, type http://localhost and instead of the dashboard you see: localhost refused to connect , This site cant be reached Very annoying, especially on a fresh install. This error usually means one of three things: Lets walk through real fixes that you can try one by one. 1. […]

The post Fix “localhost refused to connect” After Installing XAMPP / WAMP appeared first on Devnote.

]]>
You install XAMPP or WAMP, open your browser, type http://localhost and instead of the dashboard you see: localhost refused to connect , This site cant be reached Very annoying, especially on a fresh install. This error usually means one of three things:

  1. Apache is not running.
  2. Apache is running on a different port.
  3. localhost is not pointing correctly to 127.0.0.1.

Lets walk through real fixes that you can try one by one.

1. Make sure Apache is actually running

XAMPP

  1. Open the XAMPP Control Panel.
  2. Look at the Apache row.
  3. If it is not green, click the Start button.
  4. If it turns green but stops again instantly, there is usually a port conflict. Go to the next section.

WAMP

  1. Look at the WAMP icon in the system tray:
    • Red: nothing is running.
    • Orange: some services are running.
    • Green: everything is running.
  2. Left click the icon and choose Start All Services.

After starting Apache, try:

http://localhost/

If it still says “refused to connect”, continue.

2. Check for port conflicts (Apache vs another program)

By default Apache uses port 80 (HTTP) and 443 (HTTPS). If any other program is already using port 80, Apache cannot start correctly and localhost will fail.

Common culprits:

  • IIS (Internet Information Services)
  • Skype / Zoom
  • VMware / VirtualBox services
  • Other local web servers
  • Some VPN or security tools

Check which program is using port 80 (Windows)

Open Command Prompt as Administrator and run:

netstat -ano | findstr :80

Look at the last column (PID), then open Task Manager → Details tab → find that PID to see which program it is. You have two options:

  1. Stop or uninstall the conflicting program.
  2. Change Apaches port in XAMPP / WAMP.

Most people choose option 2.

3. Change Apache port in XAMPP

If port 80 is blocked and you do not want to stop the other service, change Apache to use another port like 8080.

  1. Open XAMPP Control Panel.
  2. Next to Apache, click ConfigApache (httpd.conf).
  3. Search for this line: Listen 80 Change it to: Listen 8080
  4. Search for: ServerName localhost:80 Change it to: ServerName localhost:8080
  5. Save the file.

If you also use SSL, edit httpd-ssl.conf:

  1. XAMPP Control Panel → Apache → Config → httpd-ssl.conf.
  2. Find: Listen 443 and change to something like: Listen 8443
  3. Find: <VirtualHost _default_:443> and change to: <VirtualHost _default_:8443>
  4. Save and restart Apache from the XAMPP Control Panel.

Now open:

http://localhost:8080/

If the dashboard opens, the port conflict was the problem. Remember to always include :8080 in the URL for that project or create a virtual host.

4. Change Apache port in WAMP

For WAMP, the process is similar.

  1. Left click on the WAMP icon.
  2. Go to Apache → httpd.conf.
  3. Find: Listen 80 Change to: Listen 8080
  4. Also search for: ServerName localhost:80 Change to: ServerName localhost:8080
  5. Save the file.
  6. Left click WAMP icon → Restart All Services.

Now open:

http://localhost:8080/

You should see the WAMP homepage.

5. Check the hosts file (localhost mapping)

Even if Apache is running, localhost must resolve to 127.0.0.1. If the hosts file is modified, you might get connection errors.

  1. Open Notepad as Administrator.
  2. File → Open and browse to: C:\Windows\System32\drivers\etc\hosts Change file type to “All Files” to see it.
  3. Make sure you have this line and that it is not commented: 127.0.0.1 localhost
  4. Remove any weird extra mappings for localhost.
  5. Save the file.

Test again in your browser.

6. Use the correct URL (especially after port change)

If you changed the Apache port to 8080, the correct URLs are:

  • XAMPP dashboard: http://localhost:8080/
  • WAMP homepage: http://localhost:8080/
  • Project folder: http://localhost:8080/myproject/

If you still type only http://localhost/ while Apache is listening on 8080, you will continue to see “refused to connect”.

7. Allow Apache through Windows Firewall

Sometimes the server is running but your firewall blocks incoming connections.

  1. Open Control Panel → System and Security → Windows Defender Firewall.
  2. Click Allow an app or feature through Windows Defender Firewall.
  3. Look for Apache HTTP Server or httpd.exe.
  4. Make sure Private (and Public if you need) is checked.
  5. If you do not see it, click Allow another app and browse to:
    • For XAMPP: C:\xampp\apache\bin\httpd.exe
    • For WAMP: C:\wamp64\bin\apache\apacheX.Y.Z\bin\httpd.exe
  6. Save and test http://localhost again.

8. Run panels as Administrator

Sometimes Apache cannot bind to a port because it lacks permission.

  • Right click XAMPP Control Panel → Run as administrator.
  • Or for WAMP, right click the shortcut and choose Run as administrator.

Then start Apache again.

9. Clear browser cache and check with another browser

It sounds silly, but cached redirects or HSTS rules can cause localhost to misbehave.

  • Clear cache for http://localhost.
  • Try another browser (Chrome, Firefox, Edge).
  • Also try http://127.0.0.1/ directly.

If 127.0.0.1 works but localhost does not, it is almost always a hosts file or DNS issue.

10. Quick checklist

Here is a summary you can keep for later:

  • Is Apache running in XAMPP / WAMP?
  • Is another program using port 80 or 443?
  • Did you set a custom port and forget to add it in the browser URL?
  • Does 127.0.0.1 resolve correctly in the hosts file?
  • Is the Windows Firewall or antivirus blocking Apache?
  • Are you running the control panel as Administrator?

Usually, fixing one of these points will solve the “localhost refused to connect” error on a new XAMPP or WAMP installation.

The post Fix “localhost refused to connect” After Installing XAMPP / WAMP appeared first on Devnote.

]]>
https://devnote.in/fix-localhost-refused-to-connect-after-installing-xampp-wamp/feed/ 0 5518
Composer Error: Memory exhausted When Installing Packages – Real Fix https://devnote.in/composer-error-memory-exhausted-when-installing-packages-real-fix/ https://devnote.in/composer-error-memory-exhausted-when-installing-packages-real-fix/#respond Fri, 06 Feb 2026 06:24:48 +0000 https://devnote.in/?p=5514 If you work with PHP projects long enough, you will eventually hit the dreaded Composer error: PHP Fatal error: Allowed memory size exhausted It usually happens during composer install or composer update when Composer tries to load large dependency trees or resolve versions. The good news is that this problem doesn’t mean your project is […]

The post Composer Error: Memory exhausted When Installing Packages – Real Fix appeared first on Devnote.

]]>
If you work with PHP projects long enough, you will eventually hit the dreaded Composer error: PHP Fatal error: Allowed memory size exhausted It usually happens during composer install or composer update when Composer tries to load large dependency trees or resolve versions. The good news is that this problem doesn’t mean your project is broken. It simply means PHP does not have enough memory for the process.

Let’s look at real, practical fixes that actually work.

1. Increase PHP Memory Limit Temporarily

The quickest and most commonly used solution is to give Composer extra memory only for that command.

Run:

php -d memory_limit=-1 composer install

-1 means unlimited. Use it only when needed because it disables the memory cap. You can replace install with update or any other Composer command.

Example:

php -d memory_limit=-1 composer update

2. Edit php.ini (Permanent and Safe)

A more sustainable approach is increasing the memory limit inside php.ini.

  1. Find your php.ini file:
    • Linux: /etc/php/<version>/cli/php.ini
    • Windows WAMP/XAMPP: php/php.ini
  2. Search for: memory_limit = 128M
  3. Change it to something comfortable: memory_limit = 1G

Restart Apache or PHP-FPM if you’re modifying server PHP.

Tip: Composer often needs more than 512M on large projects, so 768M or 1G is safe.

3. Add Memory Limit Config For Local Development

If you don’t want to keep editing php.ini, you can export the environment variable:

Linux / Mac:

export COMPOSER_MEMORY_LIMIT=-1

Windows PowerShell:

setx COMPOSER_MEMORY_LIMIT -1

This applies to every future Composer command without changing system-wide PHP settings.

4. Disable Xdebug While Installing Packages

Xdebug makes Composer slower and heavier. If you don’t need debugging for the install, disable it.

Method A: Temporary flag

composer install --no-dev

Method B: Disable it in php.ini

Comment out:

zend_extension=xdebug.so

Restart PHP services if needed. You can always turn it back on later.

5. Update Composer

Older Composer versions were less optimized.

Upgrade:

composer self-update

For Composer 2 users, many performance improvements are already included, so updating can significantly reduce memory usage.

6. Use Composer’s Optimizations

If your vendor folder is large, optimization helps.

Production builds:

composer install --prefer-dist --no-dev --optimize-autoloader

Development builds:

composer update --prefer-dist --optimize-autoloader

--prefer-dist skips building packages from source.

7. Increase Swap Space (Linux Servers)

Cloud instances and VPS setups often have tiny RAM. Composer can crash even with correct memory limits. Create swap:

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

This gives your system breathing room. Many hosting providers recommend at least 2 GB swap for PHP projects.

8. Don’t Use Unlimited Memory on Production Servers

Using -1 for production deployments is risky. If a process misbehaves, it can consume all available RAM and crash the server. Instead:

  • Raise memory_limit gradually
  • Use optimized Composer flags
  • Use CI/CD containers designed for build tasks

Quick Checklist

If you still get errors, ask yourself:

  • Am I running the CLI version of PHP, not web?
  • Do I really need dev dependencies?
  • Is Xdebug enabled?
  • Am I using Composer v2 or older?
  • Does the server have swap?

These five questions solve 90% of memory issues right away.

Final Thoughts

The memory exhausted error isn’t a Composer problem. It’s simply PHP hitting its limit. Increase the memory based on your environment, disable unnecessary extensions, and optimize how Composer resolves packages. Once you get these basics right, the process becomes much smoother and faster.

The post Composer Error: Memory exhausted When Installing Packages – Real Fix appeared first on Devnote.

]]>
https://devnote.in/composer-error-memory-exhausted-when-installing-packages-real-fix/feed/ 0 5514
MySQL 8 Error Unknown collation: utf8mb4_0900_ai_ci – Safe Migration Guide https://devnote.in/mysql-8-error-unknown-collation-utf8mb4_0900_ai_ci-safe-migration-guide/ https://devnote.in/mysql-8-error-unknown-collation-utf8mb4_0900_ai_ci-safe-migration-guide/#respond Wed, 04 Feb 2026 11:41:12 +0000 https://devnote.in/?p=5509 This error usually appears when you export a database from MySQL 8 and try to import it into: You’ll see something like: ERROR 1273 (HY000): Unknown collation: ‘utf8mb4_0900_ai_ci’ The reason is simple: MySQL 8 introduced new collations, and older servers don’t recognize them. Why This Happens MySQL 8 uses newer utf8mb4 collations such as: Older […]

The post MySQL 8 Error Unknown collation: utf8mb4_0900_ai_ci – Safe Migration Guide appeared first on Devnote.

]]>
This error usually appears when you export a database from MySQL 8 and try to import it into:

  • MySQL 5.7 or older
  • MariaDB (10.x, hosting panels, cPanel)
  • WAMP/XAMPP local environments
  • Shared hosting providers

You’ll see something like: ERROR 1273 (HY000): Unknown collation: ‘utf8mb4_0900_ai_ci’ The reason is simple: MySQL 8 introduced new collations, and older servers don’t recognize them.

Why This Happens

MySQL 8 uses newer utf8mb4 collations such as:

  • utf8mb4_0900_ai_ci
  • utf8mb4_0900_as_ci
  • utf8mb4_0900_as_cs

Older environments only understand older equivalents like:

  • utf8mb4_unicode_ci
  • utf8mb4_general_ci

So when you export a dump from MySQL 8, the dump file includes these new collations and your destination server throws an error.

Quick Safe Fix (Dump File Replace)

If this is a one-time import, open your .sql dump file with a good text editor and replace:

  • utf8mb4_0900_ai_ciutf8mb4_unicode_ci
  • utf8mb4_0900_as_ciutf8mb4_unicode_ci

You can also convert to utf8mb4_general_ci, but unicode_ci is more consistent.

Example search/replace:

utf8mb4_0900_ai_ci → utf8mb4_unicode_ci
utf8mb4_0900_as_ci → utf8mb4_unicode_ci

Save the file and import again.
This works in 99% of cases.

Better Fix: Export Database With Compatible Collation

Instead of editing dumps every time, export from MySQL 8 using older compatible collations.

phpMyAdmin Export

Select your database → Export → Custom options:

  • Change Collation to utf8mb4_unicode_ci
  • Uncheck “Add CREATE DATABASE” if you don’t want global settings

Export again.

CLI Export

mysqldump --default-character-set=utf8mb4 --skip-set-charset db_name > backup.sql

Then use a global find/replace only if needed.

Best Fix: Convert Database Collation Before Export

If you control the MySQL 8 database, convert tables and columns to a compatible collation before exporting.

Change database default

ALTER DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Change all tables automatically

SELECT CONCAT(
    'ALTER TABLE `', table_name, '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'
)
FROM information_schema.tables
WHERE table_schema = 'db_name';

Copy the generated ALTER statements and run them. This ensures your export is future-proof.

Important Note for MariaDB Users

MariaDB != MySQL 8.
MariaDB 10.3–10.6 still does not support the new MySQL 8 collations.

MariaDB only supports:

  • utf8mb4_unicode_ci
  • utf8mb4_general_ci
  • utf8_unicode_ci

If your production hosting uses MariaDB, always stick to these.

Convert Tables With phpMyAdmin

If you prefer GUI:

  1. Select database
  2. Select each table
  3. Operations tab
  4. Change collation → utf8mb4_unicode_ci
  5. Check “Convert table” if available

Repeat for all tables.

Fix Laravel / Application Level

If your migrations specify a new collation, downgrade them:

Schema::defaultStringLength(191);

or set:

'mysql' => [
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
]

Avoid specifying utf8mb4_0900_ai_ci unless you know the server supports it.

Quick Checklist

  • Dump from MySQL 8 → import into MySQL 5.7 / MariaDB = ❌
  • Replace new collations → utf8mb4_unicode_ci = ✔
  • Set database / tables to compatible collation before export = ✔
  • Match application-level collation with server = ✔

Once you standardize your database to utf8mb4_unicode_ci, migrations, imports, and hosting transfers go smooth with no collation errors.

The post MySQL 8 Error Unknown collation: utf8mb4_0900_ai_ci – Safe Migration Guide appeared first on Devnote.

]]>
https://devnote.in/mysql-8-error-unknown-collation-utf8mb4_0900_ai_ci-safe-migration-guide/feed/ 0 5509
WordPress Critical Error When Editing with Gutenberg – Root Cause + Fix https://devnote.in/wordpress-critical-error-when-editing-with-gutenberg-root-cause-fix/ https://devnote.in/wordpress-critical-error-when-editing-with-gutenberg-root-cause-fix/#respond Mon, 02 Feb 2026 11:12:48 +0000 https://devnote.in/?p=5505 You click Edit in Gutenberg and the page instantly crashes with: There has been a critical error on this website. This usually means a fatal PHP error or REST API failure triggered by a plugin, theme function, or server setting. Gutenberg is very JavaScript-heavy and interacts with the REST API, so anything that blocks it […]

The post WordPress Critical Error When Editing with Gutenberg – Root Cause + Fix appeared first on Devnote.

]]>
You click Edit in Gutenberg and the page instantly crashes with: There has been a critical error on this website. This usually means a fatal PHP error or REST API failure triggered by a plugin, theme function, or server setting. Gutenberg is very JavaScript-heavy and interacts with the REST API, so anything that blocks it causes a crash.

Below are the proven fixes in order of impact.

1. Enable Debug to See the Real Error

You can’t fix what you can’t see.

Edit wp-config.php:

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

Reload the Gutenberg editor.
The actual error will appear in:

/wp-content/debug.log

Typical real-world causes:

  • Fatal error in plugin
  • PHP type errors (PHP 8.x strict)
  • Missing class from a theme
  • API conflict

2. Disable Performance/Optimization Plugins

Gutenberg must load dozens of JS modules. Cache or optimization plugins break it.

Temporarily disable:

  • LiteSpeed Cache
  • WP Rocket
  • Hummingbird
  • Autoptimize
  • Asset CleanUp
  • FlyingPress
  • Nitropack

If Gutenberg loads normally, the conflict is confirmed.

Then:

  • Turn off JS combine/minify
  • Disable defer/async for admin
  • Exclude /wp-admin/, /wp-json/, block-editor*

3. Check REST API Health (This is the #1 Root Cause)

Gutenberg works via REST API endpoints.
If REST is blocked, editor crashes.

Check:
Tools → Site Health → Status

Look for:
“The REST API encountered an error”

Reasons include:

  • Security plugins blocking /wp-json/
  • Cloudflare firewall rules
  • ModSecurity blocking POST requests
  • Incorrect .htaccess rules

Fix:

  • Allow /wp-json/*
  • Whitelist your domain in firewall
  • Disable “Block REST API” options

4. Update Outdated Plugins or Block Plugins

A single block extension can break the editor.

Disable plugins one by one:

  • Kadence blocks
  • Spectra (Ultimate Addons)
  • Elementor blocks
  • Gutenberg add-ons
  • WooCommerce blocks

If the editor opens, that plugin is the culprit.
Update or replace it.

5. Fix PHP Version Issues

PHP 8.2 / 8.3 introduces stricter errors like:

  • Cannot use string offset
  • Deprecated dynamic properties
  • Missing typed return

If your theme/plugin is old, it crashes instantly.

Try:

  • Switch to PHP 8.1 temporarily
  • Update plugins/themes

Gutenberg core works on PHP 8.x. Third-party code may not.

6. Increase PHP Memory Limit

Low memory stops Gutenberg mid-load.

In wp-config.php:

define('WP_MEMORY_LIMIT', '512M');
define('WP_MAX_MEMORY_LIMIT', '512M');

Restart the editor.
For shared hosting, set this in your panel if wp-config.php is ignored.

7. Clear Browser, CDN, and Server Cache

Old JS chunks = instant crash.

Do:

  • Purge CDN (Cloudflare, Bunny, LiteSpeed CDN)
  • Clear hosting cache
  • Open Gutenberg in incognito

If it works in private mode but not normal mode → browser cache issue.

8. Theme Issues

Bad theme functions can kill the editor.

Test with:
Appearance → Themes → Activate Twenty Twenty-Four

If Gutenberg starts working, your theme has:

  • Outdated blocks
  • Fatal errors in functions.php
  • Breaking enqueue scripts

Check:

  • Custom JS/CSS
  • Block overrides
  • Old child theme code

9. Server-Level Blocking

Some servers kill Gutenberg due to security rules.

Examples:

  • Nginx or Apache limits
  • ModSecurity
  • Firewall POST body filters

If editing crashes only on large posts:

  • Increase client_max_body_size (Nginx)
  • Increase LimitRequestBody (Apache)

10. Last Resort: Reinstall Core

Won’t delete your content.

Dashboard → Updates → Reinstall WordPress

This repairs corrupted Gutenberg JS bundles.

Quick Checklist

  • Turn on debug → read debug.log
  • Check Site Health → REST API status
  • Disable optimization plugins
  • Update block plugins + theme
  • Increase PHP memory to 512M
  • Try PHP 8.1 if 8.3 breaks plugins
  • Switch to default theme
  • Purge CDN + security rules

Once the offending plugin, stale cache, or REST restriction is removed, Gutenberg loads normally again.

The post WordPress Critical Error When Editing with Gutenberg – Root Cause + Fix appeared first on Devnote.

]]>
https://devnote.in/wordpress-critical-error-when-editing-with-gutenberg-root-cause-fix/feed/ 0 5505
PHP 8.3 Fatal Error: Cannot use string offset as an array – Real World Case https://devnote.in/php-8-3-fatal-error-cannot-use-string-offset-as-an-array-real-world-case/ https://devnote.in/php-8-3-fatal-error-cannot-use-string-offset-as-an-array-real-world-case/#respond Fri, 30 Jan 2026 11:00:01 +0000 https://devnote.in/?p=5500 After upgrading to PHP 8.3 you might suddenly see this: Fatal error: Uncaught Error: Cannot use string offset as an array In older PHP versions this often slipped by as a notice or warning. PHP 8.x is stricter, so real bugs now turn into fatal errors. In simple terms, this error means: you are treating […]

The post PHP 8.3 Fatal Error: Cannot use string offset as an array – Real World Case appeared first on Devnote.

]]>
After upgrading to PHP 8.3 you might suddenly see this: Fatal error: Uncaught Error: Cannot use string offset as an array In older PHP versions this often slipped by as a notice or warning. PHP 8.x is stricter, so real bugs now turn into fatal errors.

In simple terms, this error means: you are treating a string like an array.

1. Classic real world example: form data overwritten

Imagine you receive a form and accidentally overwrite an array with a string:

$data = $_POST['user'];      // you expect an array
$data = trim($data);         // now $data is a string

echo $data['email'];         // ❌ Fatal error

$data becomes a string after trim, so $data['email'] tries to use a string offset as an array.

Fix

Keep array and string variables separate or avoid overwriting:

$user = $_POST['user'] ?? [];

$userEmail = isset($user['email']) ? trim($user['email']) : null;

Or, if the form sends flat fields:

$email = isset($_POST['email']) ? trim($_POST['email']) : null;

2. JSON decode returning string instead of array

Another real case: API or database returns JSON, but you double encode it or forget the second parameter in json_decode.

$json = getOption('settings');   // already a JSON string
$settings = json_decode($json);  // returns stdClass by default

echo $settings['theme'];         // ❌ Fatal error

json_decode without the second parameter returns an object. Accessing it with ['theme'] treats it like an array.

Fix

Decode as an associative array:

$settings = json_decode($json, true); // true = associative array

$theme = $settings['theme'] ?? 'default';

Or keep it as an object and use:

$theme = $settings->theme ?? 'default';

3. Database value overriding an array

You store settings as an array but later load a single column as a string into the same variable:

$config = [
    'mail' => [
        'host' => 'smtp.example.com',
    ],
];

$config = $pdo->query('SELECT value FROM config WHERE name="mail"')->fetchColumn();
// now $config is a string from DB

echo $config['host']; // ❌ Fatal error

Fix

Use different variables and convert the DB result back to an array if needed:

$mailConfigJson = $pdo->query(...)->fetchColumn();
$mailConfig = json_decode($mailConfigJson, true) ?? [];

echo $mailConfig['host'] ?? 'localhost';

4. Passing string into a function that expects array

Real world bug from helper functions:

function addDefaultRoles(array $roles): array
{
    $roles[] = 'viewer';
    return $roles;
}

$rolesFromDb = 'admin';        // bug: should be array
$roles = addDefaultRoles($rolesFromDb); // ❌ Type + string offset errors

PHP may complain that it cannot use string offset internally while trying to push onto the array.

Fix

Normalise types before calling:

$rolesFromDb = $rolesFromDb ? explode(',', $rolesFromDb) : [];

$roles = addDefaultRoles($rolesFromDb);

Or enforce types at the boundary of your application.

5. Safely checking types in PHP 8.3

To avoid this kind of fatal error in new code:

  • Use is_array() before accessing offsets.
  • Use the null coalescing operator (??) to provide defaults.
  • Add strict types and proper type hints.

Example:

declare(strict_types=1);

function getUserEmail(array $user): ?string
{
    return isset($user['email']) ? trim((string) $user['email']) : null;
}

$user = $_POST['user'] ?? [];
$email = getUserEmail($user);

Now if $user is not an array, PHP will throw a TypeError at the function boundary instead of failing deep inside your code.

6. Quick checklist when you see this error

  • Look at the variable just before you use $var['key'].
  • var_dump or dd($var) to see its actual type and value.
  • Stop overwriting arrays with strings in the same variable.
  • Decode JSON with json_decode($json, true) when you want arrays.
  • Normalise DB and request data as arrays before passing to functions.
  • Add type hints and strict types in new PHP 8.3 projects.

Once you treat strings and arrays consistently, this error disappears and your code becomes much easier to reason about in real applications.

The post PHP 8.3 Fatal Error: Cannot use string offset as an array – Real World Case appeared first on Devnote.

]]>
https://devnote.in/php-8-3-fatal-error-cannot-use-string-offset-as-an-array-real-world-case/feed/ 0 5500
How to Fix Nginx 413 Request Entity Too Large for Image & Video Uploads https://devnote.in/how-to-fix-nginx-413-request-entity-too-large-for-image-video-uploads/ https://devnote.in/how-to-fix-nginx-413-request-entity-too-large-for-image-video-uploads/#respond Wed, 28 Jan 2026 09:55:51 +0000 https://devnote.in/?p=5495 You try to upload a big image or video and Nginx responds with: 413 Request Entity Too Largenginx This means Nginx rejected the request before PHP or your app (Laravel, WordPress, etc.) ever saw it. The upload is simply bigger than Nginx is willing to accept. Let’s fix that safely. 1. The key setting: client_max_body_size […]

The post How to Fix Nginx 413 Request Entity Too Large for Image & Video Uploads appeared first on Devnote.

]]>
You try to upload a big image or video and Nginx responds with: 413 Request Entity Too Large
nginx
This means Nginx rejected the request before PHP or your app (Laravel, WordPress, etc.) ever saw it. The upload is simply bigger than Nginx is willing to accept.

Let’s fix that safely.

1. The key setting: client_max_body_size

Nginx controls max request size with client_max_body_size. If it is missing, the default is usually 1 MB. That is tiny for modern uploads, so large images or videos will be blocked.

You can set it in:

  • nginx.conf (global)
  • Inside an http, server, or location block

Example, for a single site:

server {
    server_name example.com;
    client_max_body_size 64M;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
}

Choose a size that fits your needs, like 20M, 64M, 100M, or more for big video uploads.

2. Reload Nginx after changing config

After editing the config file:

sudo nginx -t

If it says syntax is ok, reload:

sudo systemctl reload nginx

or on some systems:

sudo service nginx reload

Now Nginx accepts larger requests.

3. Make sure PHP upload limits match

If you only change Nginx, PHP might still reject large uploads with errors like:

POST Content-Length of X bytes exceeds the limit of Y bytes

Check your php.ini (or .user.ini on shared hosting) and set:

upload_max_filesize = 64M
post_max_size = 64M

Rules of thumb:

  • post_max_sizeupload_max_filesize
  • Both should be ≤ Nginx client_max_body_size

After editing, restart PHP-FPM:

sudo systemctl restart php8.3-fpm

(adjust version to your PHP version).

4. Put the directive in the right place

For per-site limits, use the server block for that domain:

server {
    server_name media.example.com;
    client_max_body_size 200M;
    ...
}

If you put client_max_body_size inside a location that does not match your upload URL, Nginx will still use the low default and return 413.

For a global setting, you can place it in the http block in nginx.conf:

http {
    client_max_body_size 64M;
    ...
}

5. Example for WordPress / Laravel uploads

WordPress

Uploads typically go through /wp-admin/admin-ajax.php or /wp-admin/media-new.php. A simple per-site config:

server {
    server_name example.com;
    root /var/www/example.com/public;

    client_max_body_size 64M;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}

Laravel

If your app handles uploads at /upload or through a controller, the same pattern applies:

server {
    server_name app.example.com;
    root /var/www/app/public;

    client_max_body_size 64M;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
}

The app will then just see a normal file upload within PHP limits.

6. Shared hosting or panel-based servers (Plesk, cPanel, CyberPanel)

If you do not edit Nginx by hand:

  • Look for an option like Client Max Body Size, Upload size, or Nginx directives in your panel.
  • Many panels let you paste extra directives per domain, for example: client_max_body_size 64m;
  • For PHP limits, change upload_max_filesize and post_max_size in the panel’s PHP settings.

7. Troubleshooting: still getting 413

If you still see 413 after changes:

  1. Confirm you edited the correct vhost file for that domain.
  2. Run nginx -T | grep client_max_body_size to see what values are actually active.
  3. Clear any reverse proxy cache or restart any front-facing proxy in front of Nginx (less common).
  4. Make sure there are no older client_max_body_size directives with smaller values overriding your new one in a more specific block.

8. Quick checklist

When Nginx responds with 413 Request Entity Too Large for uploads:

  • Set client_max_body_size to a higher value (for example 64M) in the right server or http block.
  • Reload Nginx after testing config with nginx -t.
  • Increase upload_max_filesize and post_max_size in PHP to the same or slightly lower value.
  • Restart PHP-FPM so new limits apply.
  • For control panels, use their interface to adjust Nginx and PHP settings instead of manual files.

With Nginx and PHP aligned on upload size, images and videos will upload successfully without the 413 error.

The post How to Fix Nginx 413 Request Entity Too Large for Image & Video Uploads appeared first on Devnote.

]]>
https://devnote.in/how-to-fix-nginx-413-request-entity-too-large-for-image-video-uploads/feed/ 0 5495
How to Fix MySQL ERROR 1698 (28000): Access denied for user ‘root’@’localhost’ https://devnote.in/how-to-fix-mysql-error-1698-28000-access-denied-for-user-rootlocalhost/ https://devnote.in/how-to-fix-mysql-error-1698-28000-access-denied-for-user-rootlocalhost/#respond Mon, 26 Jan 2026 09:35:02 +0000 https://devnote.in/?p=5491 On many modern Linux systems (especially Ubuntu/Debian with MySQL or MariaDB), you may see this when trying to log in: mysql -u root -p ERROR 1698 (28000): Access denied for user ‘root’@’localhost’ The password may be correct, but MySQL is using a different authentication method for the root user (like auth_socket), or the account has […]

The post How to Fix MySQL ERROR 1698 (28000): Access denied for user ‘root’@’localhost’ appeared first on Devnote.

]]>
On many modern Linux systems (especially Ubuntu/Debian with MySQL or MariaDB), you may see this when trying to log in: mysql -u root -p ERROR 1698 (28000): Access denied for user ‘root’@’localhost’ The password may be correct, but MySQL is using a different authentication method for the root user (like auth_socket), or the account has no password at all. Let’s walk through the common causes and fixes.

1. Understand why this error happens

ERROR 1698 (28000) means “authentication failed.” For root@localhost this usually happens because:

  1. The root account is configured to authenticate via the system user (socket/Unix auth), not with a password.
  2. You are trying to log in over TCP with a password that root is not allowed to use.
  3. The password you think is set for root is simply not the same as MySQL has stored.

So we first need to see how the root user is defined inside MySQL.

2. Log in using sudo (Linux / Ubuntu / Debian)

On Ubuntu/Debian, MySQL root often uses socket authentication. You can log in this way:

sudo mysql

If that drops you into the MySQL shell (mysql> prompt) without asking for a password, good. Now you can inspect and fix the account.

Run:

SELECT user, host, plugin FROM mysql.user;

Look for the row where user = 'root' and host = 'localhost'.

You’ll probably see something like:

root | localhost | auth_socket

or unix_socket. This means root logs in using the OS account, not a password.

3. Option A – Keep sudo login but create a separate admin user

Best practice is often to leave root as socket-auth only and create another MySQL user for apps and manual logins.

From the MySQL shell (entered via sudo mysql):

CREATE USER 'admin'@'localhost' IDENTIFIED BY 'StrongPasswordHere';

GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION;

FLUSH PRIVILEGES;

Now you can exit:

EXIT;

And log in like:

mysql -u admin -p

This avoids changing system defaults and is usually the safest.

4. Option B – Change root to use password authentication

If you really want root to use a password (for example on a local dev machine), you can switch its plugin.

From sudo mysql:

ALTER USER 'root'@'localhost'
  IDENTIFIED WITH mysql_native_password BY 'NewStrongPassword!';

FLUSH PRIVILEGES;

Now root uses mysql_native_password and you can log in with:

mysql -u root -p

Enter the new password you set.

Tip: on MySQL 8+, some distributions use caching_sha2_password. You can also use that instead of mysql_native_password if you prefer.

5. Option C – Grant root access over TCP for local tools

Some GUIs (phpMyAdmin, Adminer, HeidiSQL) connect via TCP (127.0.0.1) rather than socket. If root is only allowed from localhost with socket auth, they will fail.

If you changed root to use a password as in Option B, it should already work for both CLI and phpMyAdmin on the same server.

If you want a separate account for GUI only:

CREATE USER 'guiadmin'@'127.0.0.1' IDENTIFIED BY 'AnotherStrongPassword!';
GRANT ALL PRIVILEGES ON *.* TO 'guiadmin'@'127.0.0.1' WITH GRANT OPTION;
FLUSH PRIVILEGES;

Then use guiadmin in your GUI config.

6. Fixing the error on fresh installs (mysql_secure_installation)

On some systems, after installing MySQL, you’re prompted to run:

sudo mysql_secure_installation

If you skipped setting a password or chose “Use Unix socket authentication,” then MySQL root cannot use a password at all.

You can re-run the tool or manually set the password via sudo mysql and the ALTER USER command from Option B.

7. Check for multiple MySQL instances or wrong socket

Sometimes you have MariaDB and MySQL both installed, or multiple versions, and your mysql command talks to a different server than you expect.

Check:

which mysql
mysql --version

And in MySQL shell:

SHOW VARIABLES LIKE 'socket';

If you are editing one instance but your tools connect to another, users and passwords will not match. Make sure your client or phpMyAdmin is using the correct socket/port.

8. Quick reference commands

See all users and plugins

SELECT user, host, plugin FROM mysql.user;

Switch root to password auth

ALTER USER 'root'@'localhost'
  IDENTIFIED WITH mysql_native_password BY 'StrongPassword123!';
FLUSH PRIVILEGES;

Create new full-privilege admin user

CREATE USER 'admin'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;

9. Summary

To fix ERROR 1698 (28000): Access denied for user 'root'@'localhost':

  • Log in using sudo mysql so you bypass the password check.
  • Decide whether you want to keep root as socket-auth only or allow password login.
  • Either create a new admin user with full privileges (recommended for production) or switch the root user to mysql_native_password/caching_sha2_password and set a strong password.
  • Make sure your tools (CLI, phpMyAdmin, Laravel, etc.) point at the correct MySQL instance and host (localhost vs 127.0.0.1).

Once auth plugin, password, and host line up, the error disappears and you can connect to MySQL without issues.

The post How to Fix MySQL ERROR 1698 (28000): Access denied for user ‘root’@’localhost’ appeared first on Devnote.

]]>
https://devnote.in/how-to-fix-mysql-error-1698-28000-access-denied-for-user-rootlocalhost/feed/ 0 5491